<commit_before>#include <string>
#include <fstream>
#include <sstream>
#include <vector>
size_t letterI(const char letter, const bool is_capital) {
	int first_letter_code = static_cast<int>(is_capital ? 'А' : 'а');
	if (letter > (is_capital ? 'Е' : 'е')) {
		return static_cast<int>(letter) - first_letter_code + 2;
	}
	else {
		if (letter == (is_capital ? 'Ё' : 'ё')) {
			return 7;
		}
		return static_cast<int>(letter) - first_letter_code + 1;
	}
}
struct person {
	std::string surname;
	std::string name;
	size_t year;
	size_t i(size_t sort_i) const {
		if (sort_i < surname.length()) {
			return letterI(surname[sort_i], sort_i == 0);
		}
		else {
			return 0;
		}
	}
};
std::ostream & operator<<(std::ostream & output, person const & _person)
{
	output << _person.surname << " ";
	output << _person.name << " ";
	output << _person.year;
	return output;
}
std::istream & operator>>(std::istream & input, person & _person)
{
	input >> _person.surname;
	input >> _person.name;
	input >> _person.year;
	return input;
}
using Buckets = std::vector<std::vector<person>>;
using Persons = std::vector<person>;
class Persons_File {
public:
	Persons_File() : is_empty(true), file_size(0) {
		;
	}
	std::string file_name;
	bool is_empty;
	size_t file_size;
	std::fstream stream;
	void openNew(std::string _file_name) {
		file_name = _file_name;
		stream.open(file_name, std::ios::out);
	}
	void addToSize(person _person) {
		file_size += _person.surname.size();
		file_size += _person.name.size();
		file_size += sizeof(_person.year);
		file_size += 1 + 1 + 2;
	}
};
using Output_Files = std::vector<std::ofstream>;

class Database_Sorter {
	bool is_database_empty;
	std::string database_file_name;
	std::string vault_file_name;
public:
	Database_Sorter(std::string database_file_name, std::string output_file_name, size_t _RAM_amount)
		: database_file_name(database_file_name),
		database_file(database_file_name),
		output_file(output_file_name),
		RAM_amount(_RAM_amount),
		is_database_empty(true)
	{
		vault_file_name = "F:\\1\\temp_files\\";
	}
	void sortDatabase() {
		sortFile(database_file, database_file_name, RAM_amount + 1, 0);
	}

	~Database_Sorter() {
		database_file.close();
		output_file.close();
	}
private:
	void sortFile(std::ifstream & file, std::string file_name, size_t file_size, size_t sort_i) {
		if (file_size < RAM_amount) {
			RAMsort(file, sort_i);
		}
		else {
			std::vector<Persons_File> persons_files = stuffPersonsToFiles(file, file_name, sort_i);
			for (size_t i = 0; i < persons_files.size(); i++) {
				if (persons_files[i].file_size != 0) {
					std::ifstream temp_file(persons_files[i].file_name);
					sortFile(temp_file, persons_files[i].file_name, persons_files[i].file_size, sort_i + 1);
					temp_file.close();
				}
			}
		}
	}

	void RAMsort(std::ifstream & file, size_t sort_i) {
		persons_outputted = 0;
		persons.clear();
		readFileIntoRAM(file);
		sortPersons(persons, 0);
	}
	void readFileIntoRAM(std::ifstream & file) {
		while (!file.eof()) {
			person current_person;
			file >> current_person;
			persons.push_back(current_person);
		}
	}
	void sortPersons(Persons const & entered_persons, size_t sort_i) {
		Buckets buckets = stuffPersonsToBuckets(entered_persons, sort_i);
		if (isOnlyOneBucketFull(buckets, entered_persons, sort_i)) {
			outputBucket(entered_persons, output_file);
		}
		else {
			sortBuckets(buckets, sort_i + 1);
		}
	}
	Buckets stuffPersonsToBuckets(Persons const & persons, size_t sort_i) {
		Buckets buckets(34);
		for (auto person : persons) {
			size_t currentI = person.i(sort_i);
			buckets[currentI].push_back(person);
		}
		return buckets;
	}
	bool isOnlyOneBucketFull(Buckets const & buckets, Persons const & persons, size_t sort_i) {
		size_t first_bucket_i = persons[0].i(sort_i);
		return buckets[first_bucket_i].size() == persons.size();
	}
	void outputBucket(Persons const & bucket, std::ofstream & sorted_persons_file) {
		for (auto person : bucket) {
			outputPerson(person);
		}
	}
	void outputPerson(person _person) {
		if (is_database_empty) {
			is_database_empty = false;
		}
		else {
			output_file << std::endl;
		}
		output_file << _person;
		persons_outputted++;
	}
	void sortBuckets(Buckets const & buckets, size_t sort_i) {
		for (auto bucket : buckets) {
			if (!bucket.empty()) {
				sortPersons(bucket, sort_i);
			}
		}
	}

	std::vector<Persons_File> stuffPersonsToFiles(std::ifstream & base_file, std::string base_file_name, size_t sort_i) {
		std::vector<Persons_File> files = createDerivedFiles(base_file_name);
		while (!base_file.eof()) {
			person current_person;
			base_file >> current_person;
			size_t currentI = current_person.i(sort_i);
			if (files[currentI].is_empty) {
				files[currentI].is_empty = false;
			}
			else {
				files[currentI].stream << std::endl;
			}
			files[currentI].stream << current_person;
			files[currentI].addToSize(current_person);
		}
		for (size_t i = 0; i < files.size(); i++) {
			files[i].stream.close();
		}
		return files;
	}
	std::vector<Persons_File> createDerivedFiles(std::string base_file_name) {
		std::vector<Persons_File> files(34);
		for (size_t i = 0; i < files.size(); i++) {
			std::stringstream string_stream;
			std::string str;
			if (base_file_name == database_file_name) {
				string_stream << vault_file_name << i << ".txt";
			}
			else {
				string_stream << base_file_name << "_" << i << ".txt";
			}
			string_stream >> str;
			files[i].openNew(str);
		}
		return files;
	}
	std::vector<person> persons;
	size_t persons_outputted;
	std::ifstream database_file;
	std::ofstream output_file;
	size_t RAM_amount;
};
<commit_msg>Update Database_Sorter.hpp<commit_after>#include <string>
#include <fstream>
#include <sstream>
#include <vector>
size_t letterI(const char letter, const bool is_capital) {
	int first_letter_code = static_cast<int>(is_capital ? 'А' : 'а');
	if (letter > (is_capital ? 'Е' : 'е')) {
		return static_cast<int>(letter) - first_letter_code + 2;
	}
	else {
		if (letter == (is_capital ? 'Ё' : 'ё')) {
			return 7;
		}
		return static_cast<int>(letter) - first_letter_code + 1;
	}
}
struct person {
	std::string surname;
	std::string name;
	size_t year;
	size_t i(size_t sort_i) const {
		if (sort_i < surname.length()) {
			return letterI(surname[sort_i], sort_i == 0);
		}
		else {
			return 0;
		}
	}
};
std::ostream & operator<<(std::ostream & output, person const & _person)
{
	output << _person.surname << " ";
	output << _person.name << " ";
	output << _person.year;
	return output;
}
std::istream & operator>>(std::istream & input, person & _person)
{
	input >> _person.surname;
	input >> _person.name;
	input >> _person.year;
	return input;
}
using Buckets = std::vector<std::vector<person>>;
using Persons = std::vector<person>;
class Persons_File {
public:
	Persons_File() : is_empty(true), file_size(0) {
		;
	}
	std::string file_name;
	bool is_empty;
	size_t file_size;
	std::fstream stream;
	void openNew(std::string _file_name) {
		file_name = _file_name;
		stream.open(file_name, std::ios::out);
	}
	void addToSize(person _person) {
		file_size += _person.surname.size();
		file_size += _person.name.size();
		file_size += sizeof(_person.year);
		file_size += 1 + 1 + 2;
	}
};
using Output_Files = std::vector<std::ofstream>;

class Database_Sorter {
	bool is_database_empty;
	std::string database_file_name;
	std::string vault_file_name;
public:
	Database_Sorter(std::string database_file_name, std::string output_file_name, size_t _RAM_amount)
		: database_file_name(database_file_name),
		database_file(database_file_name),
		output_file(output_file_name),
		RAM_amount(_RAM_amount),
		is_database_empty(true)
	{
		vault_file_name = "F:\\1\\temp_files\\";
	}
	void sortDatabase() {
		sortFile(database_file, database_file_name, RAM_amount + 1, 0);
	}

	~Database_Sorter() {
		database_file.close();
		output_file.close();
	}
private:
	void sortFile(std::ifstream & file, std::string file_name, size_t file_size, size_t sort_i) {
		if (file_size < RAM_amount) {
			RAMsort(file, sort_i);
		}
		else {
			std::vector<Persons_File> persons_files = stuffPersonsToFiles(file, file_name, sort_i);
			for (size_t i = 0; i < persons_files.size(); i++) {
				if (persons_files[i].file_size != 0) {
					std::ifstream temp_file(persons_files[i].file_name);
					sortFile(temp_file, persons_files[i].file_name, persons_files[i].file_size, sort_i + 1);
					temp_file.close();
				}
			}
		}
	}

	void RAMsort(std::ifstream & file, size_t sort_i) {
		persons_outputted = 0;
		persons.clear();
		readFileIntoRAM(file);
		sortPersons(persons, sort_i);
	}
	void readFileIntoRAM(std::ifstream & file) {
		while (!file.eof()) {
			person current_person;
			file >> current_person;
			persons.push_back(current_person);
		}
	}
	void sortPersons(Persons const & entered_persons, size_t sort_i) {
		Buckets buckets = stuffPersonsToBuckets(entered_persons, sort_i);
		if (isOnlyOneBucketFull(buckets, entered_persons, sort_i)) {
			outputBucket(entered_persons, output_file);
		}
		else {
			sortBuckets(buckets, sort_i + 1);
		}
	}
	Buckets stuffPersonsToBuckets(Persons const & persons, size_t sort_i) {
		Buckets buckets(34);
		for (auto person : persons) {
			size_t currentI = person.i(sort_i);
			buckets[currentI].push_back(person);
		}
		return buckets;
	}
	bool isOnlyOneBucketFull(Buckets const & buckets, Persons const & persons, size_t sort_i) {
		size_t first_bucket_i = persons[0].i(sort_i);
		return buckets[first_bucket_i].size() == persons.size();
	}
	void outputBucket(Persons const & bucket, std::ofstream & sorted_persons_file) {
		for (auto person : bucket) {
			outputPerson(person);
		}
	}
	void outputPerson(person _person) {
		if (is_database_empty) {
			is_database_empty = false;
		}
		else {
			output_file << std::endl;
		}
		output_file << _person;
		persons_outputted++;
	}
	void sortBuckets(Buckets const & buckets, size_t sort_i) {
		for (auto bucket : buckets) {
			if (!bucket.empty()) {
				sortPersons(bucket, sort_i);
			}
		}
	}

	std::vector<Persons_File> stuffPersonsToFiles(std::ifstream & base_file, std::string base_file_name, size_t sort_i) {
		std::vector<Persons_File> files = createDerivedFiles(base_file_name);
		while (!base_file.eof()) {
			person current_person;
			base_file >> current_person;
			size_t currentI = current_person.i(sort_i);
			if (files[currentI].is_empty) {
				files[currentI].is_empty = false;
			}
			else {
				files[currentI].stream << std::endl;
			}
			files[currentI].stream << current_person;
			files[currentI].addToSize(current_person);
		}
		for (size_t i = 0; i < files.size(); i++) {
			files[i].stream.close();
		}
		return files;
	}
	std::vector<Persons_File> createDerivedFiles(std::string base_file_name) {
		std::vector<Persons_File> files(34);
		for (size_t i = 0; i < files.size(); i++) {
			std::stringstream string_stream;
			std::string str;
			if (base_file_name == database_file_name) {
				string_stream << vault_file_name << i << ".txt";
			}
			else {
				string_stream << base_file_name << "_" << i << ".txt";
			}
			string_stream >> str;
			files[i].openNew(str);
		}
		return files;
	}
	std::vector<person> persons;
	size_t persons_outputted;
	std::ifstream database_file;
	std::ofstream output_file;
	size_t RAM_amount;
};
<|endoftext|>


<commit_before>#include "PackToBin.h"
#include "PackNodeFactory.h"
#include "IPackNode.h"
#include "pack_unpack.h"
#include "spritepack.h"
#include "Lzma.h"

#include "PackPNG.h"
#include "PackPVR.h"
#include "PackPKM.h"

namespace librespacker
{

void PackToBin::PackEPE(const std::string& filepath,
						const d2d::TexturePacker& tp,
						bool compress, float scale)
{
	PackNodeFactory* factory = PackNodeFactory::Instance();
	const std::map<std::string, int>& export_set = factory->GetExportSet();

	std::vector<IPackNode*> nodes;
	factory->GetAllNodes(nodes);
	if (nodes.empty()) {
		return;
	}
	std::sort(nodes.begin(), nodes.end(), PackNodeCmp());

	std::vector<std::string> textures;
	tp.GetAllTextureFilename(textures);

	// header
	uint16_t export_n = export_set.size();
	uint16_t maxid = nodes[nodes.size() - 1]->GetID();
	uint16_t tex = textures.size();
	uint32_t unpack_sz = 0;
	unpack_sz += SIZEOF_PACK + tex * sizeof(int);
	int align_n = (maxid + 1 + 3) & ~3;
	unpack_sz += align_n * sizeof(uint8_t);
	unpack_sz += (maxid + 1) * SIZEOF_POINTER;
	for (int i = 0, n = nodes.size(); i < n; ++i) {
		unpack_sz += nodes[i]->SizeOfUnpackFromBin();
	}

	// body
	uint32_t body_sz = 0;
	for (int i = 0, n = nodes.size(); i < n; ++i) {
		body_sz += nodes[i]->SizeOfPackToBin();
	}

	// cal size
	int32_t out_sz = 0;
	out_sz += sizeof(export_n) + sizeof(maxid) + sizeof(tex) + sizeof(unpack_sz);
	out_sz += sizeof(body_sz);
	std::map<std::string, int>::const_iterator itr = export_set.begin();
	for ( ; itr != export_set.end(); ++itr) {
		out_sz += sizeof(uint16_t);		// id
		out_sz += sizeof_pack_str(itr->first);
	}
	out_sz += body_sz;

	// filling data
	uint8_t* buf = new uint8_t[out_sz];
	uint8_t* ptr = buf;
	pack(export_n, &ptr);
	pack(maxid, &ptr);
	pack(tex, &ptr);
	pack(unpack_sz, &ptr);
	pack(body_sz, &ptr);
	for (itr = export_set.begin(); itr != export_set.end(); ++itr) {
		uint16_t id = itr->second;
		pack(id, &ptr);
		pack_str(itr->first, &ptr);
	}

	for (int i = 0, n = nodes.size(); i < n; ++i) {
		nodes[i]->PackToBin(&ptr, tp, scale);
	}

	// write file
	std::locale::global(std::locale(""));
	std::ofstream fout(filepath.c_str(), std::ios::binary);
	std::locale::global(std::locale("C"));
	if (compress) {
		uint8_t* dst = NULL;
		size_t dst_sz;
		Lzma::Compress(&dst, &dst_sz, buf, out_sz);

		fout.write(reinterpret_cast<const char*>(&dst_sz), sizeof(dst_sz));
		fout.write(reinterpret_cast<const char*>(dst), dst_sz);
	} else {
		int32_t sz = -(int)out_sz;
		fout.write(reinterpret_cast<const char*>(&sz), sizeof(out_sz));
		fout.write(reinterpret_cast<const char*>(buf), out_sz);
	}
	delete[] buf;
	fout.close();
}

void PackToBin::PackEPT(const std::string& filepath, const d2d::TexturePacker& tp,
						TextureType type, int LOD, float scale)
{
	std::string ext;
	switch (type)
	{
	case TT_PNG4: case TT_PNG8:
		ext = ".png";
		break;
	case TT_PVR:
		ext = ".pvr";
		break;
	case TT_PKM:
		ext = ".pkm";
		break;
	}

	PackImage* packer;
	switch (type)
	{
	case TT_PNG4:
		packer = new PackPNG(false);
		break;
	case TT_PNG8:
		packer = new PackPNG(true);
		break;
	case TT_PVR:
		packer = new PackPVR();
		break;
	case TT_PKM:
		packer = new PackPKM();
		break;
	default:
		throw d2d::Exception("PackToBin::PackEPT unknown type: %d\n", type);
	}

	std::vector<std::string> filenames;
	tp.GetAllTextureFilename(filenames);
	for (int i = 0, n = filenames.size(); i < n; ++i)
	{
		std::string str = filenames[i];
		str = str.substr(0, str.find_last_of('.')) + ext;

		packer->Load(str);

		for (int lod = 0; lod <= LOD; ++lod)
		{
			std::string idx_str = "." + d2d::StringTools::ToString(i + 1);
			std::string scale_str = "";
			if (LOD != 0 && scale != 1) {
				scale_str = "." + d2d::StringTools::ToString((int)(scale * 100));
			}
			std::string fmt_str = ".ept";

			std::string out_filepath = filepath + idx_str + scale_str + fmt_str;
			packer->Store(out_filepath, scale);
			scale *= 0.5f;
		}
	}

	delete packer;
}

}<commit_msg>[FIXED] pack ep<commit_after>#include "PackToBin.h"
#include "PackNodeFactory.h"
#include "IPackNode.h"
#include "pack_unpack.h"
#include "spritepack.h"
#include "Lzma.h"

#include "PackPNG.h"
#include "PackPVR.h"
#include "PackPKM.h"

namespace librespacker
{

void PackToBin::PackEPE(const std::string& filepath,
						const d2d::TexturePacker& tp,
						bool compress, float scale)
{
	PackNodeFactory* factory = PackNodeFactory::Instance();
	const std::map<std::string, int>& export_set = factory->GetExportSet();

	std::vector<IPackNode*> nodes;
	factory->GetAllNodes(nodes);
	if (nodes.empty()) {
		return;
	}
	std::sort(nodes.begin(), nodes.end(), PackNodeCmp());

	std::vector<std::string> textures;
	tp.GetAllTextureFilename(textures);

	// header
	uint16_t export_n = export_set.size();
	uint16_t maxid = nodes[nodes.size() - 1]->GetID();
	uint16_t tex = textures.size();
	uint32_t unpack_sz = 0;
	unpack_sz += SIZEOF_PACK + tex * sizeof(int);
	int align_n = (maxid + 1 + 3) & ~3;
	unpack_sz += align_n * sizeof(uint8_t);
	unpack_sz += (maxid + 1) * SIZEOF_POINTER;
	for (int i = 0, n = nodes.size(); i < n; ++i) {
		unpack_sz += nodes[i]->SizeOfUnpackFromBin();
	}

	// body
	uint32_t body_sz = 0;
	for (int i = 0, n = nodes.size(); i < n; ++i) {
		body_sz += nodes[i]->SizeOfPackToBin();
	}

	// cal size
	int32_t out_sz = 0;
	out_sz += sizeof(export_n) + sizeof(maxid) + sizeof(tex) + sizeof(unpack_sz);
	out_sz += sizeof(body_sz);
	std::map<std::string, int>::const_iterator itr = export_set.begin();
	for ( ; itr != export_set.end(); ++itr) {
		out_sz += sizeof(uint16_t);		// id
		out_sz += sizeof_pack_str(itr->first);
	}
	out_sz += body_sz;

	// filling data
	uint8_t* buf = new uint8_t[out_sz];
	uint8_t* ptr = buf;
	pack(export_n, &ptr);
	pack(maxid, &ptr);
	pack(tex, &ptr);
	pack(unpack_sz, &ptr);
	pack(body_sz, &ptr);
	for (itr = export_set.begin(); itr != export_set.end(); ++itr) {
		uint16_t id = itr->second;
		pack(id, &ptr);
		pack_str(itr->first, &ptr);
	}

	for (int i = 0, n = nodes.size(); i < n; ++i) {
		nodes[i]->PackToBin(&ptr, tp, scale);
	}

	// write file
	std::locale::global(std::locale(""));
	std::ofstream fout(filepath.c_str(), std::ios::binary);
	std::locale::global(std::locale("C"));
	if (compress) {
		uint8_t* dst = NULL;
		size_t dst_sz;
		Lzma::Compress(&dst, &dst_sz, buf, out_sz);

		fout.write(reinterpret_cast<const char*>(&dst_sz), sizeof(dst_sz));
		fout.write(reinterpret_cast<const char*>(dst), dst_sz);
	} else {
		int32_t sz = -(int)out_sz;
		fout.write(reinterpret_cast<const char*>(&sz), sizeof(out_sz));
		fout.write(reinterpret_cast<const char*>(buf), out_sz);
	}
	delete[] buf;
	fout.close();
}

void PackToBin::PackEPT(const std::string& filepath, const d2d::TexturePacker& tp,
						TextureType type, int LOD, float scale)
{
	std::string ext;
	switch (type)
	{
	case TT_PNG4: case TT_PNG8:
		ext = ".png";
		break;
	case TT_PVR:
		ext = ".pvr";
		break;
	case TT_PKM:
		ext = ".pkm";
		break;
	}

	PackImage* packer;
	switch (type)
	{
	case TT_PNG4:
		packer = new PackPNG(false);
		break;
	case TT_PNG8:
		packer = new PackPNG(true);
		break;
	case TT_PVR:
		packer = new PackPVR();
		break;
	case TT_PKM:
		packer = new PackPKM();
		break;
	default:
		throw d2d::Exception("PackToBin::PackEPT unknown type: %d\n", type);
	}

	std::vector<std::string> filenames;
	tp.GetAllTextureFilename(filenames);
	for (int i = 0, n = filenames.size(); i < n; ++i)
	{
		std::string str = filenames[i];
		str = str.substr(0, str.find_last_of('.')) + ext;

		packer->Load(str);

		float pack_scale = scale;
		for (int lod = 0; lod <= LOD; ++lod)
		{
			std::string idx_str = "." + d2d::StringTools::ToString(i + 1);
			std::string scale_str = "";
			if (LOD != 0 && pack_scale != 1) {
				scale_str = "." + d2d::StringTools::ToString((int)(pack_scale * 100));
			}
			std::string fmt_str = ".ept";

			std::string out_filepath = filepath + idx_str + scale_str + fmt_str;
			packer->Store(out_filepath, pack_scale);
			pack_scale *= 0.5f;
		}
	}

	delete packer;
}

}<|endoftext|>


<commit_before>#include "PackIDMgr.h"
#include "PackNode.h"
#include "typedef.h"
#include "PackAudioIDMgr.h"

#include <simp/NodeID.h>
#include <sprite2/SymType.h>
#include <gum/FilepathHelper.h>
#include <gum/SymbolFile.h>

#include <ee/SymbolType.h>
#include <ee/SymbolFile.h>
#include <ee/ImageData.h>
#include <ee/Exception.h>
#include <ee/FileHelper.h>

#include <assert.h>

namespace esprpacker
{

CU_SINGLETON_DEFINITION(PackIDMgr)

PackIDMgr::PackIDMgr()
	: m_curr_pkg(NULL)
	, m_curr_pkg_id(-1)
{
}

void PackIDMgr::AddCurrPath(const std::string& path)
{
	if (m_curr_pkg_id != -1) {
		return;
	}

	std::string fix = gum::FilepathHelper::Format(path.c_str()).c_str();
	m_curr_paths.push_back(fix);
	if (!m_curr_pkg) {
		m_curr_pkg = ee::PackIDMgr::Instance()->QueryPkg(fix, true);
	}
}

bool PackIDMgr::IsCurrPkg(const std::string& filepath) const
{
	if (m_curr_pkg_id != -1) {
		return true;
	}
	if (filepath.empty() || filepath == ee::SYM_GROUP_TAG || filepath == SPRITE_FILEPATH) {
		return true;
	}
	if (gum::SymbolFile::Instance()->Type(filepath.c_str()) == s2::SYM_TEXTBOX) {
		return true;
	}
	for (int i = 0, n = m_curr_paths.size(); i < n; ++i) {
		if (filepath.find(m_curr_paths[i]) != std::string::npos) {
			return true;
		}
	}
	if (filepath == ee::SYM_TEXT_TAG ||
		filepath == ee::SYM_SHAPE_TAG) {
		return true;
	}
	return false;
}

bool PackIDMgr::IsCurrPkg(const PackNode* node) const
{
	int curr_pkg_id = (m_curr_pkg_id != -1 ? m_curr_pkg_id : m_curr_pkg->id);
	return curr_pkg_id == node->GetPkgID();
}

void PackIDMgr::QueryID(const std::string& filepath, int& pkg_id, int& node_id,
	                    bool is_symbol, bool force_curr) const
{
	static int NEXT_NODE_ID = 0;

	int type = ee::SymbolFile::Instance()->Type(filepath);
	if (type == s2::SYM_AUDIO)
	{
		if (force_curr)
		{
			if (m_curr_pkg_id != -1)
			{
				pkg_id = m_curr_pkg_id;
				node_id = NEXT_NODE_ID++;
			}
			else if (m_curr_pkg)
			{
				pkg_id = m_curr_pkg->id;
				node_id = NEXT_NODE_ID++;
			}
		}
		else
		{
			pkg_id = 0xfff;
			node_id = PackAudioIDMgr::Instance()->Query(filepath);
		}
		return;
	}

	if (m_curr_pkg_id != -1)
	{
		pkg_id = m_curr_pkg_id;
		node_id = NEXT_NODE_ID++;
		return;
	}
	else if (IsCurrPkg(filepath))
	{
		if (!m_curr_pkg) {
			throw ee::Exception("no curr pkg: %s\n", filepath.c_str());
		}
		assert(m_curr_pkg);
		pkg_id = m_curr_pkg->id;
		// query
		bool find = false;
		if (is_symbol)
		{
			for (auto& item : m_curr_pkg->sprs_name2id) {
				if (filepath.find(item.first) != std::string::npos) {
					node_id = simp::NodeID::GetNodeID(item.second);
					find = true;
					break;
				}
			}
		}
		if (!find) {
			GetNextFreeID(m_curr_pkg, NEXT_NODE_ID);
			node_id = NEXT_NODE_ID++;
		}
		return;
	}

	if (force_curr)
	{
		if (m_curr_pkg_id != -1)
		{
			pkg_id = m_curr_pkg_id;
			node_id = NEXT_NODE_ID++;
			return;
		}
		else if (m_curr_pkg)
		{
			pkg_id = m_curr_pkg->id;
			GetNextFreeID(m_curr_pkg, NEXT_NODE_ID);
			node_id = NEXT_NODE_ID++;
			return;
		}
	}

	const ee::PackIDMgr::Package* pkg = ee::PackIDMgr::Instance()->QueryPkg(filepath, false);
	if (!pkg)
	{
		const std::string default_sym = ee::ImageDataMgr::Instance()->GetDefaultSym();
		if (default_sym.empty()) {
			throw ee::Exception("query pkg id fail: %s", filepath.c_str());
		}
		return QueryID(default_sym, pkg_id, node_id, true);
	}

	pkg_id = pkg->id;

	std::map<std::string, uint32_t>::const_iterator itr = pkg->sprs.find(filepath);
	if (itr == pkg->sprs.end()) {
		const std::string default_sym = ee::ImageDataMgr::Instance()->GetDefaultSym();
		if (default_sym.empty()) {
			throw ee::Exception("query spr id fail: %s", filepath.c_str());
		}
		return QueryID(default_sym, pkg_id, node_id, true);
	}
	node_id = simp::NodeID::GetNodeID(itr->second);
}

void PackIDMgr::GetCurrImgCutPath(std::string& img, std::string& json, std::string& ori) const
{
	if (!m_curr_pkg) {
		return;
	}

	img = m_curr_pkg->cut_img;
	json = m_curr_pkg->cut_json;
	ori = m_curr_pkg->cut_ori;
}

void PackIDMgr::GetNextFreeID(const ee::PackIDMgr::Package* pkg, int& node_id)
{
	while (true) {
		uint32_t id = simp::NodeID::ComposeID(pkg->id, node_id);
		if (pkg->sprs_id_set.find(id) != pkg->sprs_id_set.end()) {
			++node_id;
		} else {
			break;
		}
	}
}

}<commit_msg>[FIXED] id query<commit_after>#include "PackIDMgr.h"
#include "PackNode.h"
#include "typedef.h"
#include "PackAudioIDMgr.h"

#include <simp/NodeID.h>
#include <sprite2/SymType.h>
#include <gum/FilepathHelper.h>
#include <gum/SymbolFile.h>

#include <ee/SymbolType.h>
#include <ee/SymbolFile.h>
#include <ee/ImageData.h>
#include <ee/Exception.h>
#include <ee/FileHelper.h>

#include <assert.h>

namespace esprpacker
{

CU_SINGLETON_DEFINITION(PackIDMgr)

PackIDMgr::PackIDMgr()
	: m_curr_pkg(NULL)
	, m_curr_pkg_id(-1)
{
}

void PackIDMgr::AddCurrPath(const std::string& path)
{
	if (m_curr_pkg_id != -1) {
		return;
	}

	std::string fix = gum::FilepathHelper::Format(path.c_str()).c_str();
	m_curr_paths.push_back(fix);
	if (!m_curr_pkg) {
		m_curr_pkg = ee::PackIDMgr::Instance()->QueryPkg(fix, true);
	}
}

bool PackIDMgr::IsCurrPkg(const std::string& filepath) const
{
	if (m_curr_pkg_id != -1) {
		return true;
	}
	if (filepath.empty() || filepath == ee::SYM_GROUP_TAG || filepath == SPRITE_FILEPATH) {
		return true;
	}
	if (gum::SymbolFile::Instance()->Type(filepath.c_str()) == s2::SYM_TEXTBOX) {
		return true;
	}
	for (int i = 0, n = m_curr_paths.size(); i < n; ++i) {
		if (filepath.find(m_curr_paths[i]) != std::string::npos) {
			return true;
		}
	}
	if (filepath == ee::SYM_TEXT_TAG ||
		filepath == ee::SYM_SHAPE_TAG) {
		return true;
	}
	return false;
}

bool PackIDMgr::IsCurrPkg(const PackNode* node) const
{
	int curr_pkg_id = (m_curr_pkg_id != -1 ? m_curr_pkg_id : m_curr_pkg->id);
	return curr_pkg_id == node->GetPkgID();
}

void PackIDMgr::QueryID(const std::string& filepath, int& pkg_id, int& node_id,
	                    bool is_symbol, bool force_curr) const
{
	static int NEXT_NODE_ID = 0;

	int type = ee::SymbolFile::Instance()->Type(filepath);
	if (type == s2::SYM_AUDIO)
	{
		if (force_curr)
		{
			if (m_curr_pkg_id != -1)
			{
				pkg_id = m_curr_pkg_id;
				node_id = NEXT_NODE_ID++;
			}
			else if (m_curr_pkg)
			{
				pkg_id = m_curr_pkg->id;
				node_id = NEXT_NODE_ID++;
			}
		}
		else
		{
			pkg_id = 0xfff;
			node_id = PackAudioIDMgr::Instance()->Query(filepath);
		}
		return;
	}

	if (m_curr_pkg_id != -1)
	{
		pkg_id = m_curr_pkg_id;
		node_id = NEXT_NODE_ID++;
		return;
	}
	else if (IsCurrPkg(filepath))
	{
		if (!m_curr_pkg) {
			throw ee::Exception("no curr pkg: %s\n", filepath.c_str());
		}
		assert(m_curr_pkg);
		pkg_id = m_curr_pkg->id;
		// query
		bool find = false;
		if (is_symbol)
		{
			for (auto& item : m_curr_pkg->sprs_name2id) {
				if (filepath.find("\\" + item.first) != std::string::npos) {
					node_id = simp::NodeID::GetNodeID(item.second);
					find = true;
					break;
				}
			}
		}
		if (!find) {
			GetNextFreeID(m_curr_pkg, NEXT_NODE_ID);
			node_id = NEXT_NODE_ID++;
		}
		return;
	}

	if (force_curr)
	{
		if (m_curr_pkg_id != -1)
		{
			pkg_id = m_curr_pkg_id;
			node_id = NEXT_NODE_ID++;
			return;
		}
		else if (m_curr_pkg)
		{
			pkg_id = m_curr_pkg->id;
			GetNextFreeID(m_curr_pkg, NEXT_NODE_ID);
			node_id = NEXT_NODE_ID++;
			return;
		}
	}

	const ee::PackIDMgr::Package* pkg = ee::PackIDMgr::Instance()->QueryPkg(filepath, false);
	if (!pkg)
	{
		const std::string default_sym = ee::ImageDataMgr::Instance()->GetDefaultSym();
		if (default_sym.empty()) {
			throw ee::Exception("query pkg id fail: %s", filepath.c_str());
		}
		return QueryID(default_sym, pkg_id, node_id, true);
	}

	pkg_id = pkg->id;

	std::map<std::string, uint32_t>::const_iterator itr = pkg->sprs.find(filepath);
	if (itr == pkg->sprs.end()) {
		const std::string default_sym = ee::ImageDataMgr::Instance()->GetDefaultSym();
		if (default_sym.empty()) {
			throw ee::Exception("query spr id fail: %s", filepath.c_str());
		}
		return QueryID(default_sym, pkg_id, node_id, true);
	}
	node_id = simp::NodeID::GetNodeID(itr->second);
}

void PackIDMgr::GetCurrImgCutPath(std::string& img, std::string& json, std::string& ori) const
{
	if (!m_curr_pkg) {
		return;
	}

	img = m_curr_pkg->cut_img;
	json = m_curr_pkg->cut_json;
	ori = m_curr_pkg->cut_ori;
}

void PackIDMgr::GetNextFreeID(const ee::PackIDMgr::Package* pkg, int& node_id)
{
	while (true) {
		uint32_t id = simp::NodeID::ComposeID(pkg->id, node_id);
		if (pkg->sprs_id_set.find(id) != pkg->sprs_id_set.end()) {
			++node_id;
		} else {
			break;
		}
	}
}

}<|endoftext|>


<commit_before>//
// web_socket.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2013 Jack (jack at gmail dot com)
//
// Distributed under the GNU Affero General Public License, Version 3.0. (See accompanying
// file LICENSE or copy at http://www.gnu.org/licenses/agpl-3.0.txt)
//

#ifndef AVWS_WEB_SOCKET_HPP
#define AVWS_WEB_SOCKET_HPP

#include "avws.hpp"

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <boost/asio/detail/config.hpp>

namespace avws {

using boost::asio::ip::tcp;

// 这是一个web_socket接口实现.
class web_socket : public boost::noncopyable
{
public:
	// Constructor.
	AVWS_DECL explicit web_socket(boost::asio::io_service &io)
		: m_ioservice(io)
	{
	}

	// Destructor.
	AVWS_DECL virtual ~web_socket()
	{
	}

	// 设置请求选项信息, 必须在open或accept之前设置.
	AVWS_DECL void request_options(const request_opts &options);
	// 返回当前连接的请求选项.
	AVWS_DECL request_opts request_options(void) const;
	// 返回当前连接的回复选项信息.
	AVWS_DECL response_opts response_options(void) const;

	// 在open或accept的步骤里, 实行了websocket认证.

	// 打开url.
	AVWS_DECL void open(const url &u)
	{
		boost::system::error_code ec;
		open(u, ec);
		if (ec)
		{
			boost::throw_exception(boost::system::system_error(ec));
		}
	}

	AVWS_DECL void open(const url &u, boost::system::error_code &ec)
	{
		// 保存url相关的信息.
		m_protocol = u.protocol();
		m_url = u;

		// 输出打开的链接地址.
		LOG_DEBUG("Sync open url \'" << u.to_string() << "\'");

		// 判断不支持的协议, 并返回错误.
		if (m_protocol != "ws")
		{
			LOG_ERROR("Unsupported scheme \'" << m_protocol << "\'");
			ec = boost::asio::error::operation_not_supported;
			return;
		}

	}

	// 异步打开url.
	template <typename Handler>
	void async_open(const url &u, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 关闭底层连接.
	AVWS_DECL void close();
	AVWS_DECL void close(boost::system::error_code &ec);

	// 在websocket中, 数据封装成frame由发送函数实现, 上层用户无需操心.
	// 至于是文本还是二进制, 由request_options确定.
	// 由于websocket是基于message设计, 所以, write_some每次实际上将
	// 是发送一条完整的消息.

	// 同步发送消息.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers);
	// 同步发送消息.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步发送消息.
	template <typename ConstBufferSequence, typename Handler>
	void async_write_some(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 同步接收消息.
	template <typename MutableBufferSequence>
	std::size_t read_some(const MutableBufferSequence &buffers);
	// 同步接收消息.
	template <typename MutableBufferSequence>
	std::size_t read_some(const MutableBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步接收消息.
	template <typename MutableBufferSequence, typename Handler>
	void async_read_some(const MutableBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

protected:

	// io_service引用, 由用户在构造时传入, 并由用户运行.
	boost::asio::io_service& m_ioservice;

	// 当前url.
	url m_url;

	// 当前协议.
	std::string m_protocol;
};

} // namespace avws

#endif // AVWS_WEB_SOCKET_HPP
<commit_msg>add resolve_host and connect_host<commit_after>//
// web_socket.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2013 Jack (jack at gmail dot com)
//
// Distributed under the GNU Affero General Public License, Version 3.0. (See accompanying
// file LICENSE or copy at http://www.gnu.org/licenses/agpl-3.0.txt)
//

#ifndef AVWS_WEB_SOCKET_HPP
#define AVWS_WEB_SOCKET_HPP

#include "avws.hpp"

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <boost/asio/detail/config.hpp>

namespace avws {

using boost::asio::ip::tcp;

// 这是一个web_socket接口实现.
class web_socket : public boost::noncopyable
{
public:
	// Constructor.
	AVWS_DECL explicit web_socket(boost::asio::io_service &io)
		: m_io_service(io)
		, m_resolver(io)
		, m_socket(io)
	{
	}

	// Destructor.
	AVWS_DECL virtual ~web_socket()
	{
	}

	// 设置请求选项信息, 必须在open或accept之前设置.
	AVWS_DECL void request_options(const request_opts &options);
	// 返回当前连接的请求选项.
	AVWS_DECL request_opts request_options(void) const;
	// 返回当前连接的回复选项信息.
	AVWS_DECL response_opts response_options(void) const;

	// 在open或accept的步骤里, 实行了websocket认证.

	// 打开url.
	AVWS_DECL void open(const url &u)
	{
		boost::system::error_code ec;
		open(u, ec);
		if (ec)
		{
			boost::throw_exception(boost::system::system_error(ec));
		}
	}

	// 同步查询url中host信息, 并返回相应的iterator.
	tcp::resolver::iterator resolve_host(tcp::resolver &resolver,
		const url &u, boost::system::error_code &ec)
	{
		std::ostringstream port_string;
		port_string.imbue(std::locale("C"));
		port_string << u.port();
		tcp::resolver::query query(u.host(), port_string.str());
		return resolver.resolve(query, ec);
	}

	// 同步连接到endpoint_iterator所指的host.
	template <typename Socket>
	void connect_host(Socket &s,
		tcp::resolver::iterator &endpoint_iterator, boost::system::error_code &ec)
	{
		tcp::resolver::iterator end;
		// 尝试连接解析出来的代理服务器地址.
		ec = boost::asio::error::host_not_found;
		while (ec && endpoint_iterator != end)
		{
			s.close(ec);
			s.connect(*endpoint_iterator++, ec);
		}
	}

	AVWS_DECL void open(const url &u, boost::system::error_code &ec)
	{
		// 保存url相关的信息.
		m_protocol = u.protocol();
		m_url = u;

		// 输出打开的链接地址.
		LOG_DEBUG("Sync open url \'" << u.to_string() << "\'");

		// 判断不支持的协议, 并返回错误.
		if (m_protocol != "ws")
		{
			LOG_ERROR("Unsupported scheme \'" << m_protocol << "\'");
			ec = boost::asio::error::operation_not_supported;
			return;
		}

		// 解析url主机
		tcp::resolver::iterator endpoint_iterator = resolve_host(m_resolver, m_url, ec);
		if (ec)	// 解析域名出错, 直接返回相关错误描述.
		{
			LOG_ERROR("Resolve \'" << m_url.host() <<
				"\', error message \'" << ec.message() << "\'");
			return;
		}

		connect_host(m_socket, endpoint_iterator, ec);
		if (ec)
		{
			LOG_ERROR("Connect to server \'" << m_url.host() << ":" << m_url.port() <<
				"\', error message \'" << ec.message() << "\'");
			return;
		}
		else
		{
			LOG_DEBUG("Connect to server \'" << m_url.host() << ":" << m_url.port() << "\'.");
		}

		// 连接成功, 开始认证逻辑.

	}

	// 异步打开url.
	template <typename Handler>
	void async_open(const url &u, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 关闭底层连接.
	AVWS_DECL void close();
	AVWS_DECL void close(boost::system::error_code &ec);

	// 在websocket中, 数据封装成frame由发送函数实现, 上层用户无需操心.
	// 至于是文本还是二进制, 由request_options确定.
	// 由于websocket是基于message设计, 所以, write_some每次实际上将
	// 是发送一条完整的消息.

	// 同步发送消息.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers);
	// 同步发送消息.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步发送消息.
	template <typename ConstBufferSequence, typename Handler>
	void async_write_some(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 同步接收消息.
	template <typename MutableBufferSequence>
	std::size_t read_some(const MutableBufferSequence &buffers);
	// 同步接收消息.
	template <typename MutableBufferSequence>
	std::size_t read_some(const MutableBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步接收消息.
	template <typename MutableBufferSequence, typename Handler>
	void async_read_some(const MutableBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

protected:

	// io_service引用, 由用户在构造时传入, 并由用户运行.
	boost::asio::io_service& m_io_service;

	// 解析HOST.
	tcp::resolver m_resolver;

	// 当前socket对象.
	tcp::socket m_socket;

	// 当前url.
	url m_url;

	// 当前协议.
	std::string m_protocol;
};

} // namespace avws

#endif // AVWS_WEB_SOCKET_HPP
<|endoftext|>


<commit_before>// @(#)root/cont:$Id$
// Author: Fons Rademakers   26/05/99

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TExMap                                                               //
//                                                                      //
// This class stores a (key,value) pair using an external hash.         //
// The (key,value) are Long64_t's and therefore can contain object      //
// pointers or any longs. The map uses an open addressing hashing       //
// method (linear probing).                                             //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TExMap.h"
#include "TError.h"
#include "TMathBase.h"
#include <string.h>

ClassImp(TExMap)

////////////////////////////////////////////////////////////////////////////////
/// Create a TExMap.

TExMap::TExMap(Int_t mapSize)
{
   // needed for automatic resizing to guarantee that one slot is always empty
   if (mapSize < 4) mapSize = 5;

   switch (mapSize) {
      // Avoid calling NextPrime for the common case:
      case   5: fSize = 5; break;
      case 503: fSize = 503; break;
      default:
         fSize  = (Int_t)TMath::NextPrime(mapSize);
   }
   fTable = new Assoc_t [fSize];

   memset(fTable,0,sizeof(Assoc_t)*fSize);
   fTally = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Copy constructor.

TExMap::TExMap(const TExMap &map) : TObject(map)
{
   fSize  = map.fSize;
   fTally = map.fTally;
   fTable = new Assoc_t [fSize];
   memcpy(fTable, map.fTable, fSize*sizeof(Assoc_t));
}

////////////////////////////////////////////////////////////////////////////////
/// Assignement operator.

TExMap& TExMap::operator=(const TExMap &map)
{
   if (this != &map) {
      TObject::operator=(map);
      fSize  = map.fSize;
      fTally = map.fTally;
      fTable = new Assoc_t [fSize];
      memcpy(fTable, map.fTable, fSize*sizeof(Assoc_t));
   }
   return *this;
}

////////////////////////////////////////////////////////////////////////////////
/// Delete TExMap.

TExMap::~TExMap()
{
   delete [] fTable; fTable = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Add an (key,value) pair to the table. The key should be unique.

void TExMap::Add(ULong64_t hash, Long64_t key, Long64_t value)
{
   if (!fTable) return;

   Int_t slot = FindElement(hash, key);
   if (!fTable[slot].InUse()) {
      fTable[slot].SetHash(hash);
      fTable[slot].fKey = key;
      fTable[slot].fValue = value;
      fTally++;
      if (HighWaterMark())
         Expand(2 * fSize);
   } else
      Error("Add", "key %lld is not unique", key);
}

////////////////////////////////////////////////////////////////////////////////
/// Add an (key,value) pair to the table. The key should be unique.
/// If the 'slot' is open, use it to store the value,
/// otherwise revert to Add(hash,key,value)
/// This is usually used in conjuction with GetValue wiht 3 parameters:
/// if ((idx = (ULong64_t)fMap->GetValue(hash, key, slot)) != 0) {
///    ...
/// } else {
///    fMap->AddAt(slot,hash,key,value);
/// }

void TExMap::AddAt(UInt_t slot, ULong64_t hash, Long64_t key, Long64_t value)
{
   if (!fTable) return;

   if (!fTable[slot].InUse()) {
      fTable[slot].SetHash(hash);
      fTable[slot].fKey = key;
      fTable[slot].fValue = value;
      fTally++;
      if (HighWaterMark())
         Expand(2 * fSize);
   } else {
      Add(hash,key,value);
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Return a reference to the value belonging to the key with the
/// specified hash value. If the key does not exist it will be added.
/// NOTE: the reference will be invalidated an Expand() triggered by
/// an Add() or another operator() call.

Long64_t &TExMap::operator()(ULong64_t hash, Long64_t key)
{
   static Long64_t err;
   if (!fTable) {
      Error("operator()", "fTable==0, should never happen");
      return err;
   }

   Int_t slot = FindElement(hash, key);
   if (!fTable[slot].InUse()) {
      fTable[slot].SetHash(hash);
      fTable[slot].fKey = key;
      fTable[slot].fValue = 0;
      fTally++;
      if (HighWaterMark()) {
         Expand(2 * fSize);
         slot = FindElement(hash, key);
      }
   }
   return fTable[slot].fValue;
}

////////////////////////////////////////////////////////////////////////////////
/// Delete all entries stored in the TExMap.

void TExMap::Delete(Option_t *)
{
   memset(fTable,0,sizeof(Assoc_t)*fSize);
   fTally = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Return the value belonging to specified key and hash value. If key not
/// found return 0.

Long64_t TExMap::GetValue(ULong64_t hash, Long64_t key)
{
   if (!fTable) return 0;

   hash |= 0x1;
   Int_t slot = Int_t(hash % fSize);
   Int_t firstSlot = slot;
   do {
      if (!fTable[slot].InUse()) return 0;
      if (key == fTable[slot].fKey) return fTable[slot].fValue;
      if (++slot == fSize) slot = 0;
   } while (firstSlot != slot);

   Error("GetValue", "table full");
   return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Return the value belonging to specified key and hash value. If key not
/// found return 0.
/// In 'slot', return the index of the slot used or the first empty slot.
/// (to be used with AddAt).

Long64_t TExMap::GetValue(ULong64_t hash, Long64_t key, UInt_t &slot)
{
   if (!fTable) { slot = 0; return 0; }

   hash |= 0x1;
   slot = Int_t(hash % fSize);
   UInt_t firstSlot = slot;
   do {
      if (!fTable[slot].InUse()) return 0;
      if (key == fTable[slot].fKey) return fTable[slot].fValue;
      if (++slot == (UInt_t)fSize) slot = 0;
   } while (firstSlot != slot);

   Error("GetValue", "table full");
   return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Remove entry with specified key from the TExMap.

void TExMap::Remove(ULong64_t hash, Long64_t key)
{
   if (!fTable)
      return;

   Int_t i = FindElement(hash, key);
   if (!fTable[i].InUse()) {
      Error("Remove", "key %lld not found at %d", key, i);
      return;
   }

   fTable[i].Clear();
   FixCollisions(i);
   fTally--;
}

////////////////////////////////////////////////////////////////////////////////
/// Find an entry with specified hash and key in the TExMap.
/// Returns the slot of the key or the next empty slot.

Int_t TExMap::FindElement(ULong64_t hash, Long64_t key)
{
   if (!fTable) return 0;

   hash |= 0x1;
   Int_t slot = Int_t(hash % fSize);
   Int_t firstSlot = slot;
   do {
      if (!fTable[slot].InUse()) return slot;
      if (key == fTable[slot].fKey) return slot;
      if (++slot == fSize) slot = 0;
   } while (firstSlot != slot);

   Error("FindElement", "table full");
   return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Rehash the map in case an entry has been removed.

void TExMap::FixCollisions(Int_t index)
{
   Int_t oldIndex, nextIndex;
   Assoc_t nextObject;

   for (oldIndex = index+1; ;oldIndex++) {
      if (oldIndex >= fSize)
         oldIndex = 0;
      nextObject = fTable[oldIndex];
      if (!nextObject.InUse())
         break;
      nextIndex = FindElement(nextObject.GetHash(), nextObject.fKey);
      if (nextIndex != oldIndex) {
         fTable[nextIndex] = nextObject;
         fTable[oldIndex].Clear();
      }
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Expand the TExMap.

void TExMap::Expand(Int_t newSize)
{
   Int_t i;
   Assoc_t *oldTable = fTable;
   Int_t oldsize = fSize;
   newSize = (Int_t)TMath::NextPrime(newSize);
   fTable  = new Assoc_t [newSize];

   for (i = newSize; --i >= 0;) {
      fTable[i].Clear();
   }

   fSize = newSize;
   for (i = 0; i < oldsize; i++)
      if (oldTable[i].InUse()) {
         Int_t slot = FindElement(oldTable[i].GetHash(), oldTable[i].fKey);
         if (!fTable[slot].InUse())
            fTable[slot] = oldTable[i];
         else
            Error("Expand", "slot %d not empty (should never happen)", slot);
      }
   delete [] oldTable;
}

////////////////////////////////////////////////////////////////////////////////
/// Stream all objects in the collection to or from the I/O buffer.

void TExMap::Streamer(TBuffer &b)
{
   Int_t i;
   UInt_t R__s, R__c;

   if (b.IsReading()) {
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      TObject::Streamer(b);

      if (R__v >= 3) {
         // new custom streamer with slots indices stored (Long64_t version).
         Int_t size, tally;
         b >> size;
         Expand(size);
         b >> tally;
         Int_t slot;
         ULong64_t hash;
         Long64_t key, value;
         for (i = 0; i < tally; ++i) {
            b >> slot;
            b >> hash;
            b >> key;
            b >> value;
            Assoc_t *assoc = fTable + slot;
            assoc->SetHash(hash);
            assoc->fKey = key;
            assoc->fValue = value;
         }
         fTally = tally;
      } else if (R__v >= 2) {
         // new custom streamer with slots indices stored.
         Int_t size, tally;
         b >> size;
         Expand(size);
         b >> tally;
         Int_t slot;
         ULong_t hash;
         Long_t key, value;
         for (i = 0; i < tally; ++i) {
            b >> slot;
            b >> hash;
            b >> key;
            b >> value;
            Assoc_t* assoc = fTable + slot;
            assoc->SetHash(hash);
            assoc->fKey = key;
            assoc->fValue = value;
         }
         fTally = tally;
      } else {
         // old custom streamer that only allows slow dynamic rebuild of TExMap:
         Int_t n;
         b >> n;
         ULong_t hash;
         Long_t key, value;
         for (i = 0; i < n; i++) {
            b >> hash;
            b >> key;
            b >> value;
            Add(hash, key, value);
         }
      }
      b.CheckByteCount(R__s, R__c, TExMap::IsA());
   } else {
      R__c = b.WriteVersion(TExMap::IsA(), kTRUE);
      // new custom streamer stores slots indices
      TObject::Streamer(b);
      b << fSize;
      b << fTally;

      for (i=0; i < fSize; i++) {
         if (!fTable[i].InUse()) continue;
         b << i;
         b << fTable[i].GetHash();
         b << fTable[i].fKey;
         b << fTable[i].fValue;
      }
      b.SetByteCount(R__c, kTRUE);
   }
}

ClassImp(TExMapIter)

////////////////////////////////////////////////////////////////////////////////
/// Create TExMap iterator.

TExMapIter::TExMapIter(const TExMap *map) : fMap(map), fCursor(0)
{
}

////////////////////////////////////////////////////////////////////////////////
/// Overloaded assignment operator.

TExMapIter &TExMapIter::operator=(const TExMapIter &rhs)
{
   if (this != &rhs) {
      fMap    = rhs.fMap;
      fCursor = rhs.fCursor;
   }
   return *this;
}

////////////////////////////////////////////////////////////////////////////////
/// Get next entry from TExMap. Returns kFALSE at end of map.

Bool_t TExMapIter::Next(ULong64_t &hash, Long64_t &key, Long64_t &value)
{
   while (fCursor < fMap->fSize && !fMap->fTable[fCursor].InUse())
      fCursor++;

   if (fCursor == fMap->fSize)
      return kFALSE;

   hash  = fMap->fTable[fCursor].GetHash();
   key   = fMap->fTable[fCursor].fKey;
   value = fMap->fTable[fCursor].fValue;
   fCursor++;

   return kTRUE;
}

////////////////////////////////////////////////////////////////////////////////
/// Get next entry from TExMap. Returns kFALSE at end of map.

Bool_t TExMapIter::Next(Long64_t &key, Long64_t &value)
{
   ULong64_t hash;
   return Next(hash, key, value);
}
<commit_msg>Doxygen & spell check<commit_after>// @(#)root/cont:$Id$
// Author: Fons Rademakers   26/05/99

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

/** \class TExMap
This class stores a (key,value) pair using an external hash.
The (key,value) are Long64_t's and therefore can contain object
pointers or any longs. The map uses an open addressing hashing
method (linear probing).
*/

#include "TExMap.h"
#include "TError.h"
#include "TMathBase.h"
#include <string.h>

ClassImp(TExMap)

////////////////////////////////////////////////////////////////////////////////
/// Create a TExMap.

TExMap::TExMap(Int_t mapSize)
{
   // needed for automatic resizing to guarantee that one slot is always empty
   if (mapSize < 4) mapSize = 5;

   switch (mapSize) {
      // Avoid calling NextPrime for the common case:
      case   5: fSize = 5; break;
      case 503: fSize = 503; break;
      default:
         fSize  = (Int_t)TMath::NextPrime(mapSize);
   }
   fTable = new Assoc_t [fSize];

   memset(fTable,0,sizeof(Assoc_t)*fSize);
   fTally = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Copy constructor.

TExMap::TExMap(const TExMap &map) : TObject(map)
{
   fSize  = map.fSize;
   fTally = map.fTally;
   fTable = new Assoc_t [fSize];
   memcpy(fTable, map.fTable, fSize*sizeof(Assoc_t));
}

////////////////////////////////////////////////////////////////////////////////
/// Assignment operator.

TExMap& TExMap::operator=(const TExMap &map)
{
   if (this != &map) {
      TObject::operator=(map);
      fSize  = map.fSize;
      fTally = map.fTally;
      fTable = new Assoc_t [fSize];
      memcpy(fTable, map.fTable, fSize*sizeof(Assoc_t));
   }
   return *this;
}

////////////////////////////////////////////////////////////////////////////////
/// Delete TExMap.

TExMap::~TExMap()
{
   delete [] fTable; fTable = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Add an (key,value) pair to the table. The key should be unique.

void TExMap::Add(ULong64_t hash, Long64_t key, Long64_t value)
{
   if (!fTable) return;

   Int_t slot = FindElement(hash, key);
   if (!fTable[slot].InUse()) {
      fTable[slot].SetHash(hash);
      fTable[slot].fKey = key;
      fTable[slot].fValue = value;
      fTally++;
      if (HighWaterMark())
         Expand(2 * fSize);
   } else
      Error("Add", "key %lld is not unique", key);
}

////////////////////////////////////////////////////////////////////////////////
/// Add an (key,value) pair to the table. The key should be unique.
/// If the 'slot' is open, use it to store the value,
/// otherwise revert to Add(hash,key,value)
/// This is usually used in conjunction with GetValue with 3 parameters:
/// ~~~ {.cpp}
/// if ((idx = (ULong64_t)fMap->GetValue(hash, key, slot)) != 0) {
///    ...
/// } else {
///    fMap->AddAt(slot,hash,key,value);
/// }
/// ~~~

void TExMap::AddAt(UInt_t slot, ULong64_t hash, Long64_t key, Long64_t value)
{
   if (!fTable) return;

   if (!fTable[slot].InUse()) {
      fTable[slot].SetHash(hash);
      fTable[slot].fKey = key;
      fTable[slot].fValue = value;
      fTally++;
      if (HighWaterMark())
         Expand(2 * fSize);
   } else {
      Add(hash,key,value);
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Return a reference to the value belonging to the key with the
/// specified hash value. If the key does not exist it will be added.
/// NOTE: the reference will be invalidated an Expand() triggered by
/// an Add() or another operator() call.

Long64_t &TExMap::operator()(ULong64_t hash, Long64_t key)
{
   static Long64_t err;
   if (!fTable) {
      Error("operator()", "fTable==0, should never happen");
      return err;
   }

   Int_t slot = FindElement(hash, key);
   if (!fTable[slot].InUse()) {
      fTable[slot].SetHash(hash);
      fTable[slot].fKey = key;
      fTable[slot].fValue = 0;
      fTally++;
      if (HighWaterMark()) {
         Expand(2 * fSize);
         slot = FindElement(hash, key);
      }
   }
   return fTable[slot].fValue;
}

////////////////////////////////////////////////////////////////////////////////
/// Delete all entries stored in the TExMap.

void TExMap::Delete(Option_t *)
{
   memset(fTable,0,sizeof(Assoc_t)*fSize);
   fTally = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Return the value belonging to specified key and hash value. If key not
/// found return 0.

Long64_t TExMap::GetValue(ULong64_t hash, Long64_t key)
{
   if (!fTable) return 0;

   hash |= 0x1;
   Int_t slot = Int_t(hash % fSize);
   Int_t firstSlot = slot;
   do {
      if (!fTable[slot].InUse()) return 0;
      if (key == fTable[slot].fKey) return fTable[slot].fValue;
      if (++slot == fSize) slot = 0;
   } while (firstSlot != slot);

   Error("GetValue", "table full");
   return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Return the value belonging to specified key and hash value. If key not
/// found return 0.
/// In 'slot', return the index of the slot used or the first empty slot.
/// (to be used with AddAt).

Long64_t TExMap::GetValue(ULong64_t hash, Long64_t key, UInt_t &slot)
{
   if (!fTable) { slot = 0; return 0; }

   hash |= 0x1;
   slot = Int_t(hash % fSize);
   UInt_t firstSlot = slot;
   do {
      if (!fTable[slot].InUse()) return 0;
      if (key == fTable[slot].fKey) return fTable[slot].fValue;
      if (++slot == (UInt_t)fSize) slot = 0;
   } while (firstSlot != slot);

   Error("GetValue", "table full");
   return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Remove entry with specified key from the TExMap.

void TExMap::Remove(ULong64_t hash, Long64_t key)
{
   if (!fTable)
      return;

   Int_t i = FindElement(hash, key);
   if (!fTable[i].InUse()) {
      Error("Remove", "key %lld not found at %d", key, i);
      return;
   }

   fTable[i].Clear();
   FixCollisions(i);
   fTally--;
}

////////////////////////////////////////////////////////////////////////////////
/// Find an entry with specified hash and key in the TExMap.
/// Returns the slot of the key or the next empty slot.

Int_t TExMap::FindElement(ULong64_t hash, Long64_t key)
{
   if (!fTable) return 0;

   hash |= 0x1;
   Int_t slot = Int_t(hash % fSize);
   Int_t firstSlot = slot;
   do {
      if (!fTable[slot].InUse()) return slot;
      if (key == fTable[slot].fKey) return slot;
      if (++slot == fSize) slot = 0;
   } while (firstSlot != slot);

   Error("FindElement", "table full");
   return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Rehash the map in case an entry has been removed.

void TExMap::FixCollisions(Int_t index)
{
   Int_t oldIndex, nextIndex;
   Assoc_t nextObject;

   for (oldIndex = index+1; ;oldIndex++) {
      if (oldIndex >= fSize)
         oldIndex = 0;
      nextObject = fTable[oldIndex];
      if (!nextObject.InUse())
         break;
      nextIndex = FindElement(nextObject.GetHash(), nextObject.fKey);
      if (nextIndex != oldIndex) {
         fTable[nextIndex] = nextObject;
         fTable[oldIndex].Clear();
      }
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Expand the TExMap.

void TExMap::Expand(Int_t newSize)
{
   Int_t i;
   Assoc_t *oldTable = fTable;
   Int_t oldsize = fSize;
   newSize = (Int_t)TMath::NextPrime(newSize);
   fTable  = new Assoc_t [newSize];

   for (i = newSize; --i >= 0;) {
      fTable[i].Clear();
   }

   fSize = newSize;
   for (i = 0; i < oldsize; i++)
      if (oldTable[i].InUse()) {
         Int_t slot = FindElement(oldTable[i].GetHash(), oldTable[i].fKey);
         if (!fTable[slot].InUse())
            fTable[slot] = oldTable[i];
         else
            Error("Expand", "slot %d not empty (should never happen)", slot);
      }
   delete [] oldTable;
}

////////////////////////////////////////////////////////////////////////////////
/// Stream all objects in the collection to or from the I/O buffer.

void TExMap::Streamer(TBuffer &b)
{
   Int_t i;
   UInt_t R__s, R__c;

   if (b.IsReading()) {
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      TObject::Streamer(b);

      if (R__v >= 3) {
         // new custom streamer with slots indices stored (Long64_t version).
         Int_t size, tally;
         b >> size;
         Expand(size);
         b >> tally;
         Int_t slot;
         ULong64_t hash;
         Long64_t key, value;
         for (i = 0; i < tally; ++i) {
            b >> slot;
            b >> hash;
            b >> key;
            b >> value;
            Assoc_t *assoc = fTable + slot;
            assoc->SetHash(hash);
            assoc->fKey = key;
            assoc->fValue = value;
         }
         fTally = tally;
      } else if (R__v >= 2) {
         // new custom streamer with slots indices stored.
         Int_t size, tally;
         b >> size;
         Expand(size);
         b >> tally;
         Int_t slot;
         ULong_t hash;
         Long_t key, value;
         for (i = 0; i < tally; ++i) {
            b >> slot;
            b >> hash;
            b >> key;
            b >> value;
            Assoc_t* assoc = fTable + slot;
            assoc->SetHash(hash);
            assoc->fKey = key;
            assoc->fValue = value;
         }
         fTally = tally;
      } else {
         // old custom streamer that only allows slow dynamic rebuild of TExMap:
         Int_t n;
         b >> n;
         ULong_t hash;
         Long_t key, value;
         for (i = 0; i < n; i++) {
            b >> hash;
            b >> key;
            b >> value;
            Add(hash, key, value);
         }
      }
      b.CheckByteCount(R__s, R__c, TExMap::IsA());
   } else {
      R__c = b.WriteVersion(TExMap::IsA(), kTRUE);
      // new custom streamer stores slots indices
      TObject::Streamer(b);
      b << fSize;
      b << fTally;

      for (i=0; i < fSize; i++) {
         if (!fTable[i].InUse()) continue;
         b << i;
         b << fTable[i].GetHash();
         b << fTable[i].fKey;
         b << fTable[i].fValue;
      }
      b.SetByteCount(R__c, kTRUE);
   }
}

ClassImp(TExMapIter)

////////////////////////////////////////////////////////////////////////////////
/// Create TExMap iterator.

TExMapIter::TExMapIter(const TExMap *map) : fMap(map), fCursor(0)
{
}

////////////////////////////////////////////////////////////////////////////////
/// Overloaded assignment operator.

TExMapIter &TExMapIter::operator=(const TExMapIter &rhs)
{
   if (this != &rhs) {
      fMap    = rhs.fMap;
      fCursor = rhs.fCursor;
   }
   return *this;
}

////////////////////////////////////////////////////////////////////////////////
/// Get next entry from TExMap. Returns kFALSE at end of map.

Bool_t TExMapIter::Next(ULong64_t &hash, Long64_t &key, Long64_t &value)
{
   while (fCursor < fMap->fSize && !fMap->fTable[fCursor].InUse())
      fCursor++;

   if (fCursor == fMap->fSize)
      return kFALSE;

   hash  = fMap->fTable[fCursor].GetHash();
   key   = fMap->fTable[fCursor].fKey;
   value = fMap->fTable[fCursor].fValue;
   fCursor++;

   return kTRUE;
}

////////////////////////////////////////////////////////////////////////////////
/// Get next entry from TExMap. Returns kFALSE at end of map.

Bool_t TExMapIter::Next(Long64_t &key, Long64_t &value)
{
   ULong64_t hash;
   return Next(hash, key, value);
}
<|endoftext|>


<commit_before>#include "ffmpeg_video_source.h"
extern "C" {
#include <libavutil/imgutils.h>
}

namespace gg
{

VideoSourceFFmpeg::VideoSourceFFmpeg()
{
    // nop
}

VideoSourceFFmpeg::VideoSourceFFmpeg(std::string source_path,
                                     enum ColourSpace colour_space)
    : IVideoSource(colour_space)
    , src_filename(nullptr)
    , fmt_ctx(nullptr)
    , video_stream_idx(-1)
    , refcount(0)
    , video_stream(nullptr)
    , video_dec_ctx(nullptr)
    , _avframe(nullptr)
    , video_frame_count(0)
{
    int ret = 0;
    std::string error_msg = "";

    src_filename = const_cast<char *>(source_path.c_str());

    av_register_all();

    if (avformat_open_input(&fmt_ctx, src_filename, nullptr, nullptr) < 0)
    {
        error_msg.append("Could not open video source ")
                 .append(source_path);
        throw VideoSourceError(error_msg);
    }

    if (avformat_find_stream_info(fmt_ctx, nullptr) < 0)
        throw VideoSourceError("Could not find stream information");

    if (open_codec_context(&video_stream_idx, fmt_ctx,
                           AVMEDIA_TYPE_VIDEO, error_msg) >= 0)
    {
        video_stream = fmt_ctx->streams[video_stream_idx];
        video_dec_ctx = video_stream->codec;

        /* allocate image where the decoded image will be put */
        width = video_dec_ctx->width;
        height = video_dec_ctx->height;
        pix_fmt = video_dec_ctx->pix_fmt;
        ret = av_image_alloc(video_dst_data, video_dst_linesize,
                             width, height, pix_fmt, 1);
        if (ret < 0)
            throw VideoSourceError("Could not allocate"
                                   " raw video buffer");
        video_dst_bufsize = ret;
    }
    else
        throw VideoSourceError(error_msg);

    // TODO
    av_dump_format(fmt_ctx, 0, src_filename, 0);

    if (video_stream == nullptr)
        throw VideoSourceError("Could not find video stream in source");

    _avframe = av_frame_alloc();
    if (_avframe == nullptr)
        throw VideoSourceError("Could not allocate frame");

    /* initialize packet, set data to NULL, let the demuxer fill it */
    av_init_packet(&pkt);
    pkt.data = nullptr;
    pkt.size = 0;
}

VideoSourceFFmpeg::~VideoSourceFFmpeg()
{
    // TODO: is this part needed?
    int got_frame;
    /* flush cached frames */
    pkt.data = nullptr;
    pkt.size = 0;
    do
        decode_packet(&got_frame, 1);
    while (got_frame);

    avcodec_close(video_dec_ctx);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&_avframe);
    av_free(video_dst_data[0]);
    video_dst_bufsize = 0;
}

bool VideoSourceFFmpeg::get_frame_dimensions(int & width, int & height)
{
    // TODO
    return false;
}

bool VideoSourceFFmpeg::get_frame(VideoFrame & frame)
{
    if (av_read_frame(fmt_ctx, &pkt) < 0)
        return false;

    int ret = 0, got_frame;
    bool success = true;
    AVPacket orig_pkt = pkt;
    size_t passes = 0;
    do
    {
        ret = decode_packet(&got_frame, 0);
        if (ret < 0)
        {
            success = false;
            break;
        }
        pkt.data += ret;
        pkt.size -= ret;

        /* copy decoded frame to destination buffer:
         * this is required since rawvideo expects non aligned data */
        av_image_copy(video_dst_data, video_dst_linesize,
                      (const uint8_t **)(_avframe->data), _avframe->linesize,
                      pix_fmt, width, height);

        passes++;
    }
    while (pkt.size > 0);
    av_packet_unref(&orig_pkt);

    if (not success)
        return false;

    // TODO - when are there multiple passes?
    if (passes != 1)
        return false;

    frame.init_from_specs(video_dst_data[0], video_dst_bufsize, width, height);
    return true;
}

double VideoSourceFFmpeg::get_frame_rate()
{
    // TODO
    return 0.0;
}

void VideoSourceFFmpeg::set_sub_frame(int x, int y, int width, int height)
{
    // TODO
}

void VideoSourceFFmpeg::get_full_frame()
{
    // TODO
}

int VideoSourceFFmpeg::open_codec_context(
        int * stream_idx, AVFormatContext * fmt_ctx,
        enum AVMediaType type, std::string & error_msg)
{
    // TODO
    return -1;
}

int VideoSourceFFmpeg::decode_packet(int * got_frame, int cached)
{
    // TODO
    return -1;
}

}
<commit_msg>Issue #74: implemented open_codec_context<commit_after>#include "ffmpeg_video_source.h"
extern "C" {
#include <libavutil/imgutils.h>
}

namespace gg
{

VideoSourceFFmpeg::VideoSourceFFmpeg()
{
    // nop
}

VideoSourceFFmpeg::VideoSourceFFmpeg(std::string source_path,
                                     enum ColourSpace colour_space)
    : IVideoSource(colour_space)
    , src_filename(nullptr)
    , fmt_ctx(nullptr)
    , video_stream_idx(-1)
    , refcount(0)
    , video_stream(nullptr)
    , video_dec_ctx(nullptr)
    , _avframe(nullptr)
    , video_frame_count(0)
{
    int ret = 0;
    std::string error_msg = "";

    src_filename = const_cast<char *>(source_path.c_str());

    av_register_all();

    if (avformat_open_input(&fmt_ctx, src_filename, nullptr, nullptr) < 0)
    {
        error_msg.append("Could not open video source ")
                 .append(source_path);
        throw VideoSourceError(error_msg);
    }

    if (avformat_find_stream_info(fmt_ctx, nullptr) < 0)
        throw VideoSourceError("Could not find stream information");

    if (open_codec_context(&video_stream_idx, fmt_ctx,
                           AVMEDIA_TYPE_VIDEO, error_msg) >= 0)
    {
        video_stream = fmt_ctx->streams[video_stream_idx];
        video_dec_ctx = video_stream->codec;

        /* allocate image where the decoded image will be put */
        width = video_dec_ctx->width;
        height = video_dec_ctx->height;
        pix_fmt = video_dec_ctx->pix_fmt;
        ret = av_image_alloc(video_dst_data, video_dst_linesize,
                             width, height, pix_fmt, 1);
        if (ret < 0)
            throw VideoSourceError("Could not allocate"
                                   " raw video buffer");
        video_dst_bufsize = ret;
    }
    else
        throw VideoSourceError(error_msg);

    // TODO
    av_dump_format(fmt_ctx, 0, src_filename, 0);

    if (video_stream == nullptr)
        throw VideoSourceError("Could not find video stream in source");

    _avframe = av_frame_alloc();
    if (_avframe == nullptr)
        throw VideoSourceError("Could not allocate frame");

    /* initialize packet, set data to NULL, let the demuxer fill it */
    av_init_packet(&pkt);
    pkt.data = nullptr;
    pkt.size = 0;
}

VideoSourceFFmpeg::~VideoSourceFFmpeg()
{
    // TODO: is this part needed?
    int got_frame;
    /* flush cached frames */
    pkt.data = nullptr;
    pkt.size = 0;
    do
        decode_packet(&got_frame, 1);
    while (got_frame);

    avcodec_close(video_dec_ctx);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&_avframe);
    av_free(video_dst_data[0]);
    video_dst_bufsize = 0;
}

bool VideoSourceFFmpeg::get_frame_dimensions(int & width, int & height)
{
    // TODO
    return false;
}

bool VideoSourceFFmpeg::get_frame(VideoFrame & frame)
{
    if (av_read_frame(fmt_ctx, &pkt) < 0)
        return false;

    int ret = 0, got_frame;
    bool success = true;
    AVPacket orig_pkt = pkt;
    size_t passes = 0;
    do
    {
        ret = decode_packet(&got_frame, 0);
        if (ret < 0)
        {
            success = false;
            break;
        }
        pkt.data += ret;
        pkt.size -= ret;

        /* copy decoded frame to destination buffer:
         * this is required since rawvideo expects non aligned data */
        av_image_copy(video_dst_data, video_dst_linesize,
                      (const uint8_t **)(_avframe->data), _avframe->linesize,
                      pix_fmt, width, height);

        passes++;
    }
    while (pkt.size > 0);
    av_packet_unref(&orig_pkt);

    if (not success)
        return false;

    // TODO - when are there multiple passes?
    if (passes != 1)
        return false;

    frame.init_from_specs(video_dst_data[0], video_dst_bufsize, width, height);
    return true;
}

double VideoSourceFFmpeg::get_frame_rate()
{
    // TODO
    return 0.0;
}

void VideoSourceFFmpeg::set_sub_frame(int x, int y, int width, int height)
{
    // TODO
}

void VideoSourceFFmpeg::get_full_frame()
{
    // TODO
}

int VideoSourceFFmpeg::open_codec_context(
        int * stream_idx, AVFormatContext * fmt_ctx,
        enum AVMediaType type, std::string & error_msg)
{
    int ret, stream_index;
    AVStream * st;
    AVCodecContext * dec_ctx = nullptr;
    AVCodec * dec = nullptr;
    AVDictionary * opts = nullptr;

    ret = av_find_best_stream(fmt_ctx, type, -1, -1, nullptr, 0);
    if (ret < 0)
    {
        error_msg.append("Could not find ")
                 .append(av_get_media_type_string(type))
                 .append(" stream in source ")
                 .append(src_filename);
        return ret;
    }
    else
    {
        stream_index = ret;
        st = fmt_ctx->streams[stream_index];

        /* find decoder for the stream */
        dec_ctx = st->codec;
        dec = avcodec_find_decoder(dec_ctx->codec_id);
        if (!dec)
        {
            error_msg.append("Failed to find ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return AVERROR(EINVAL);
        }

        /* Init the decoders, with or without reference counting */
        av_dict_set(&opts, "refcounted_frames", refcount ? "1" : "0", 0);
        if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0)
        {
            error_msg.append("Failed to open ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return ret;
        }
        *stream_idx = stream_index;
    }

    return 0;
}

int VideoSourceFFmpeg::decode_packet(int * got_frame, int cached)
{
    // TODO
    return -1;
}

}
<|endoftext|>


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

#include "chrome/browser/gtk/location_bar_view_gtk.h"

#include <string>

#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/gfx/gtk_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/alternate_nav_url_fetcher.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/gtk_util.h"
#include "chrome/common/page_transition_types.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/glue/window_open_disposition.h"

namespace {

// Top and bottom padding/margin
// We are positioned with a little bit of extra space that we don't use now.
const int kTopMargin = 1;
const int kBottomMargin = 1;
// We draw a border on the top and bottom (but not on left or right).
const int kBorderThickness = 1;

// Left and right padding/margin.
// no icon/text  : 4px url_text 4px
//                 [4px|url text|4px] <hide ssl icon> <hide ev text>
// with icon     : 4px url_text 6px ssl_icon 8px
//                 [4px|url text|4px] [2px|ssl icon|8px] <hide ev text>
// with icon/text: 4px url_text 6px ssl_icon 8px ev_text 4px]
//                 [4px|url text|4px] [2px|ssl icon|8px] [ev text|4px]

// We don't want to edit control's text to be right against the edge.
const int kEditLeftRightPadding = 4;

// Padding around the security icon.
const int kSecurityIconPaddingLeft = 2;
const int kSecurityIconPaddingRight = 8;

const int kEvTextPaddingRight = 4;

// TODO(deanm): Eventually this should be painted with the background png
// image, but for now we get pretty close by just drawing a solid border.
const GdkColor kBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4);

const GdkColor kEvTextColor = GDK_COLOR_RGB(0x00, 0x96, 0x14);  // Green.

}  // namespace

// static
const GdkColor LocationBarViewGtk::kBackgroundColorByLevel[3] = {
  GDK_COLOR_RGB(255, 245, 195),  // SecurityLevel SECURE: Yellow.
  GDK_COLOR_RGB(255, 255, 255),  // SecurityLevel NORMAL: White.
  GDK_COLOR_RGB(255, 255, 255),  // SecurityLevel INSECURE: White.
};

LocationBarViewGtk::LocationBarViewGtk(CommandUpdater* command_updater,
    ToolbarModel* toolbar_model, AutocompletePopupPositioner* popup_positioner)
    : security_icon_align_(NULL),
      security_lock_icon_image_(NULL),
      security_warning_icon_image_(NULL),
      info_label_align_(NULL),
      info_label_(NULL),
      profile_(NULL),
      command_updater_(command_updater),
      toolbar_model_(toolbar_model),
      popup_positioner_(popup_positioner),
      disposition_(CURRENT_TAB),
      transition_(PageTransition::TYPED) {
}

LocationBarViewGtk::~LocationBarViewGtk() {
  // All of our widgets should have be children of / owned by the alignment.
  hbox_.Destroy();
}

void LocationBarViewGtk::Init() {
  location_entry_.reset(new AutocompleteEditViewGtk(this,
                                                    toolbar_model_,
                                                    profile_,
                                                    command_updater_,
                                                    popup_positioner_));
  location_entry_->Init();

  hbox_.Own(gtk_hbox_new(FALSE, 0));
  // We will paint for the alignment, to paint the background and border.
  gtk_widget_set_app_paintable(hbox_.get(), TRUE);
  // Have GTK double buffer around the expose signal.
  gtk_widget_set_double_buffered(hbox_.get(), TRUE);
  // Redraw the whole location bar when it changes size (e.g., when toggling
  // the home button on/off.
  gtk_widget_set_redraw_on_allocate(hbox_.get(), TRUE);

  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  security_lock_icon_image_ = gtk_image_new_from_pixbuf(
      rb.GetPixbufNamed(IDR_LOCK));
  gtk_widget_hide(GTK_WIDGET(security_lock_icon_image_));
  security_warning_icon_image_ = gtk_image_new_from_pixbuf(
      rb.GetPixbufNamed(IDR_WARNING));
  gtk_widget_hide(GTK_WIDGET(security_warning_icon_image_));

  info_label_ = gtk_label_new(NULL);
  gtk_widget_modify_base(info_label_, GTK_STATE_NORMAL,
      &LocationBarViewGtk::kBackgroundColorByLevel[0]);
  gtk_widget_hide(GTK_WIDGET(info_label_));

  g_signal_connect(hbox_.get(), "expose-event",
                   G_CALLBACK(&HandleExposeThunk), this);

  GtkWidget* align = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(align),
                            kTopMargin + kBorderThickness,
                            kBottomMargin + kBorderThickness,
                            kEditLeftRightPadding, kEditLeftRightPadding);
  gtk_container_add(GTK_CONTAINER(align), location_entry_->widget());
  gtk_box_pack_start(GTK_BOX(hbox_.get()), align, TRUE, TRUE, 0);

  // Pack info_label_ and security icons in hbox.  We hide/show them
  // by SetSecurityIcon() and SetInfoText().
  info_label_align_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(info_label_align_),
                            kTopMargin + kBorderThickness,
                            kBottomMargin + kBorderThickness,
                            0, kEvTextPaddingRight);
  gtk_container_add(GTK_CONTAINER(info_label_align_), info_label_);
  gtk_box_pack_end(GTK_BOX(hbox_.get()), info_label_align_, FALSE, FALSE, 0);

  GtkWidget* security_icon_box = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(security_icon_box),
                     security_lock_icon_image_, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(security_icon_box),
                     security_warning_icon_image_, FALSE, FALSE, 0);

  security_icon_align_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(security_icon_align_),
                            kTopMargin + kBorderThickness,
                            kBottomMargin + kBorderThickness,
                            kSecurityIconPaddingLeft,
                            kSecurityIconPaddingRight);
  gtk_container_add(GTK_CONTAINER(security_icon_align_), security_icon_box);
  gtk_box_pack_end(GTK_BOX(hbox_.get()), security_icon_align_, FALSE, FALSE, 0);
}

void LocationBarViewGtk::SetProfile(Profile* profile) {
  profile_ = profile;
}

void LocationBarViewGtk::Update(const TabContents* contents) {
  SetSecurityIcon(toolbar_model_->GetIcon());
  SetInfoText();
  location_entry_->Update(contents);
  // The security level (background color) could have changed, etc.
  gtk_widget_queue_draw(hbox_.get());
}

void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url,
      WindowOpenDisposition disposition,
      PageTransition::Type transition,
      const GURL& alternate_nav_url) {
  if (!url.is_valid())
    return;

  location_input_ = UTF8ToWide(url.spec());
  disposition_ = disposition;
  transition_ = transition;

  if (!command_updater_)
    return;

  if (!alternate_nav_url.is_valid()) {
    command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    return;
  }

  scoped_ptr<AlternateNavURLFetcher> fetcher(
      new AlternateNavURLFetcher(alternate_nav_url));
  // The AlternateNavURLFetcher will listen for the pending navigation
  // notification that will be issued as a result of the "open URL." It
  // will automatically install itself into that navigation controller.
  command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
  if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
    // I'm not sure this should be reachable, but I'm not also sure enough
    // that it shouldn't to stick in a NOTREACHED().  In any case, this is
    // harmless; we can simply let the fetcher get deleted here and it will
    // clean itself up properly.
  } else {
    fetcher.release();  // The navigation controller will delete the fetcher.
  }
}

void LocationBarViewGtk::OnChanged() {
  // TODO(deanm): Here is where we would do layout when we have things like
  // the keyword display, ssl icons, etc.
}

void LocationBarViewGtk::OnInputInProgress(bool in_progress) {
  // This is identical to the Windows code, except that we don't proxy the call
  // back through the Toolbar, and just access the model here.
  // The edit should make sure we're only notified when something changes.
  DCHECK(toolbar_model_->input_in_progress() != in_progress);

  toolbar_model_->set_input_in_progress(in_progress);
  Update(NULL);
}

SkBitmap LocationBarViewGtk::GetFavIcon() const {
  NOTIMPLEMENTED();
  return SkBitmap();
}

std::wstring LocationBarViewGtk::GetTitle() const {
  NOTIMPLEMENTED();
  return std::wstring();
}

void LocationBarViewGtk::ShowFirstRunBubble(bool use_OEM_bubble) {
  NOTIMPLEMENTED();
}

std::wstring LocationBarViewGtk::GetInputString() const {
  return location_input_;
}

WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const {
  return disposition_;
}

PageTransition::Type LocationBarViewGtk::GetPageTransition() const {
  return transition_;
}

void LocationBarViewGtk::AcceptInput() {
  AcceptInputWithDisposition(CURRENT_TAB);
}

void LocationBarViewGtk::AcceptInputWithDisposition(
    WindowOpenDisposition disposition) {
  location_entry_->model()->AcceptInput(disposition, false);
}

void LocationBarViewGtk::FocusLocation() {
  location_entry_->SetFocus();
  location_entry_->SelectAll(true);
}

void LocationBarViewGtk::FocusSearch() {
  location_entry_->SetFocus();
  location_entry_->SetForcedQuery();
}

void LocationBarViewGtk::UpdatePageActions() {
  // http://code.google.com/p/chromium/issues/detail?id=11973
}

void LocationBarViewGtk::SaveStateToContents(TabContents* contents) {
  // http://crbug.com/9225
}

void LocationBarViewGtk::Revert() {
  location_entry_->RevertAll();
}

gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget,
                                          GdkEventExpose* event) {
  GdkDrawable* drawable = GDK_DRAWABLE(event->window);
  GdkGC* gc = gdk_gc_new(drawable);

  GdkRectangle* alloc_rect = &hbox_->allocation;

  // The area outside of our margin, which includes the border.
  GdkRectangle inner_rect = {
      alloc_rect->x,
      alloc_rect->y + kTopMargin,
      alloc_rect->width,
      alloc_rect->height - kTopMargin - kBottomMargin};

  // Some of our calculations are a bit sloppy.  Since we draw on our parent
  // window, set a clip to make sure that we don't draw outside.
  gdk_gc_set_clip_rectangle(gc, &inner_rect);

  // Draw our 1px border.  TODO(deanm): Maybe this would be cleaner as an
  // overdrawn stroked rect with a clip to the allocation?
  gdk_gc_set_rgb_fg_color(gc, &kBorderColor);
  gdk_draw_rectangle(drawable, gc, TRUE,
                     inner_rect.x,
                     inner_rect.y,
                     inner_rect.width,
                     kBorderThickness);
  gdk_draw_rectangle(drawable, gc, TRUE,
                     inner_rect.x,
                     inner_rect.y + inner_rect.height - kBorderThickness,
                     inner_rect.width,
                     kBorderThickness);

  // Draw the background within the border.
  gdk_gc_set_rgb_fg_color(gc,
      &kBackgroundColorByLevel[toolbar_model_->GetSchemeSecurityLevel()]);
  gdk_draw_rectangle(drawable, gc, TRUE,
                     inner_rect.x,
                     inner_rect.y + kBorderThickness,
                     inner_rect.width,
                     inner_rect.height - (kBorderThickness * 2));

  g_object_unref(gc);

  return FALSE;  // Continue propagating the expose.
}

void LocationBarViewGtk::SetSecurityIcon(ToolbarModel::Icon icon) {
  gtk_widget_hide(GTK_WIDGET(security_lock_icon_image_));
  gtk_widget_hide(GTK_WIDGET(security_warning_icon_image_));
  if (icon != ToolbarModel::NO_ICON)
    gtk_widget_show(GTK_WIDGET(security_icon_align_));
  else
    gtk_widget_hide(GTK_WIDGET(security_icon_align_));
  switch (icon) {
    case ToolbarModel::LOCK_ICON:
      gtk_widget_show(GTK_WIDGET(security_lock_icon_image_));
      break;
    case ToolbarModel::WARNING_ICON:
      gtk_widget_show(GTK_WIDGET(security_warning_icon_image_));
      break;
    case ToolbarModel::NO_ICON:
      break;
    default:
      NOTREACHED();
      break;
  }
}

void LocationBarViewGtk::SetInfoText() {
  std::wstring info_text, info_tooltip;
  ToolbarModel::InfoTextType info_text_type =
      toolbar_model_->GetInfoText(&info_text, &info_tooltip);
  if (info_text_type == ToolbarModel::INFO_EV_TEXT) {
    gtk_widget_modify_fg(GTK_WIDGET(info_label_), GTK_STATE_NORMAL,
                         &kEvTextColor);
    gtk_widget_show(GTK_WIDGET(info_label_align_));
  } else {
    DCHECK_EQ(info_text_type, ToolbarModel::INFO_NO_INFO);
    DCHECK(info_text.empty());
    // Clear info_text.  Should we reset the fg here?
    gtk_widget_hide(GTK_WIDGET(info_label_align_));
  }
  gtk_label_set_text(GTK_LABEL(info_label_), WideToUTF8(info_text).c_str());
  gtk_widget_set_tooltip_text(GTK_WIDGET(info_label_),
                              WideToUTF8(info_tooltip).c_str());
}
<commit_msg>Make the Linux location bar SSL icon padding match Windows.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/location_bar_view_gtk.h"

#include <string>

#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/gfx/gtk_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/alternate_nav_url_fetcher.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/gtk_util.h"
#include "chrome/common/page_transition_types.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/glue/window_open_disposition.h"

namespace {

// Top and bottom padding/margin
// We are positioned with a little bit of extra space that we don't use now.
const int kTopMargin = 1;
const int kBottomMargin = 1;
// We draw a border on the top and bottom (but not on left or right).
const int kBorderThickness = 1;

// Left and right padding/margin.
// no icon/text  : 4px url_text 4px
//                 [4px|url text|4px] <hide ssl icon> <hide ev text>
// with icon     : 4px url_text 6px ssl_icon 8px
//                 [4px|url text|4px] [2px|ssl icon|8px] <hide ev text>
// with icon/text: 4px url_text 6px ssl_icon 8px ev_text 4px]
//                 [4px|url text|4px] [2px|ssl icon|8px] [ev text|4px]

// We don't want to edit control's text to be right against the edge.
const int kEditLeftRightPadding = 4;

// Padding around the security icon.
const int kSecurityIconPaddingLeft = 0;
const int kSecurityIconPaddingRight = 6;

const int kEvTextPaddingRight = 4;

// TODO(deanm): Eventually this should be painted with the background png
// image, but for now we get pretty close by just drawing a solid border.
const GdkColor kBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4);

const GdkColor kEvTextColor = GDK_COLOR_RGB(0x00, 0x96, 0x14);  // Green.

}  // namespace

// static
const GdkColor LocationBarViewGtk::kBackgroundColorByLevel[3] = {
  GDK_COLOR_RGB(255, 245, 195),  // SecurityLevel SECURE: Yellow.
  GDK_COLOR_RGB(255, 255, 255),  // SecurityLevel NORMAL: White.
  GDK_COLOR_RGB(255, 255, 255),  // SecurityLevel INSECURE: White.
};

LocationBarViewGtk::LocationBarViewGtk(CommandUpdater* command_updater,
    ToolbarModel* toolbar_model, AutocompletePopupPositioner* popup_positioner)
    : security_icon_align_(NULL),
      security_lock_icon_image_(NULL),
      security_warning_icon_image_(NULL),
      info_label_align_(NULL),
      info_label_(NULL),
      profile_(NULL),
      command_updater_(command_updater),
      toolbar_model_(toolbar_model),
      popup_positioner_(popup_positioner),
      disposition_(CURRENT_TAB),
      transition_(PageTransition::TYPED) {
}

LocationBarViewGtk::~LocationBarViewGtk() {
  // All of our widgets should have be children of / owned by the alignment.
  hbox_.Destroy();
}

void LocationBarViewGtk::Init() {
  location_entry_.reset(new AutocompleteEditViewGtk(this,
                                                    toolbar_model_,
                                                    profile_,
                                                    command_updater_,
                                                    popup_positioner_));
  location_entry_->Init();

  hbox_.Own(gtk_hbox_new(FALSE, 0));
  // We will paint for the alignment, to paint the background and border.
  gtk_widget_set_app_paintable(hbox_.get(), TRUE);
  // Have GTK double buffer around the expose signal.
  gtk_widget_set_double_buffered(hbox_.get(), TRUE);
  // Redraw the whole location bar when it changes size (e.g., when toggling
  // the home button on/off.
  gtk_widget_set_redraw_on_allocate(hbox_.get(), TRUE);

  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  security_lock_icon_image_ = gtk_image_new_from_pixbuf(
      rb.GetPixbufNamed(IDR_LOCK));
  gtk_widget_hide(GTK_WIDGET(security_lock_icon_image_));
  security_warning_icon_image_ = gtk_image_new_from_pixbuf(
      rb.GetPixbufNamed(IDR_WARNING));
  gtk_widget_hide(GTK_WIDGET(security_warning_icon_image_));

  info_label_ = gtk_label_new(NULL);
  gtk_widget_modify_base(info_label_, GTK_STATE_NORMAL,
      &LocationBarViewGtk::kBackgroundColorByLevel[0]);
  gtk_widget_hide(GTK_WIDGET(info_label_));

  g_signal_connect(hbox_.get(), "expose-event",
                   G_CALLBACK(&HandleExposeThunk), this);

  GtkWidget* align = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(align),
                            kTopMargin + kBorderThickness,
                            kBottomMargin + kBorderThickness,
                            kEditLeftRightPadding, kEditLeftRightPadding);
  gtk_container_add(GTK_CONTAINER(align), location_entry_->widget());
  gtk_box_pack_start(GTK_BOX(hbox_.get()), align, TRUE, TRUE, 0);

  // Pack info_label_ and security icons in hbox.  We hide/show them
  // by SetSecurityIcon() and SetInfoText().
  info_label_align_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(info_label_align_),
                            kTopMargin + kBorderThickness,
                            kBottomMargin + kBorderThickness,
                            0, kEvTextPaddingRight);
  gtk_container_add(GTK_CONTAINER(info_label_align_), info_label_);
  gtk_box_pack_end(GTK_BOX(hbox_.get()), info_label_align_, FALSE, FALSE, 0);

  GtkWidget* security_icon_box = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(security_icon_box),
                     security_lock_icon_image_, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(security_icon_box),
                     security_warning_icon_image_, FALSE, FALSE, 0);

  security_icon_align_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(security_icon_align_),
                            kTopMargin + kBorderThickness,
                            kBottomMargin + kBorderThickness,
                            kSecurityIconPaddingLeft,
                            kSecurityIconPaddingRight);
  gtk_container_add(GTK_CONTAINER(security_icon_align_), security_icon_box);
  gtk_box_pack_end(GTK_BOX(hbox_.get()), security_icon_align_, FALSE, FALSE, 0);
}

void LocationBarViewGtk::SetProfile(Profile* profile) {
  profile_ = profile;
}

void LocationBarViewGtk::Update(const TabContents* contents) {
  SetSecurityIcon(toolbar_model_->GetIcon());
  SetInfoText();
  location_entry_->Update(contents);
  // The security level (background color) could have changed, etc.
  gtk_widget_queue_draw(hbox_.get());
}

void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url,
      WindowOpenDisposition disposition,
      PageTransition::Type transition,
      const GURL& alternate_nav_url) {
  if (!url.is_valid())
    return;

  location_input_ = UTF8ToWide(url.spec());
  disposition_ = disposition;
  transition_ = transition;

  if (!command_updater_)
    return;

  if (!alternate_nav_url.is_valid()) {
    command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    return;
  }

  scoped_ptr<AlternateNavURLFetcher> fetcher(
      new AlternateNavURLFetcher(alternate_nav_url));
  // The AlternateNavURLFetcher will listen for the pending navigation
  // notification that will be issued as a result of the "open URL." It
  // will automatically install itself into that navigation controller.
  command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
  if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
    // I'm not sure this should be reachable, but I'm not also sure enough
    // that it shouldn't to stick in a NOTREACHED().  In any case, this is
    // harmless; we can simply let the fetcher get deleted here and it will
    // clean itself up properly.
  } else {
    fetcher.release();  // The navigation controller will delete the fetcher.
  }
}

void LocationBarViewGtk::OnChanged() {
  // TODO(deanm): Here is where we would do layout when we have things like
  // the keyword display, ssl icons, etc.
}

void LocationBarViewGtk::OnInputInProgress(bool in_progress) {
  // This is identical to the Windows code, except that we don't proxy the call
  // back through the Toolbar, and just access the model here.
  // The edit should make sure we're only notified when something changes.
  DCHECK(toolbar_model_->input_in_progress() != in_progress);

  toolbar_model_->set_input_in_progress(in_progress);
  Update(NULL);
}

SkBitmap LocationBarViewGtk::GetFavIcon() const {
  NOTIMPLEMENTED();
  return SkBitmap();
}

std::wstring LocationBarViewGtk::GetTitle() const {
  NOTIMPLEMENTED();
  return std::wstring();
}

void LocationBarViewGtk::ShowFirstRunBubble(bool use_OEM_bubble) {
  NOTIMPLEMENTED();
}

std::wstring LocationBarViewGtk::GetInputString() const {
  return location_input_;
}

WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const {
  return disposition_;
}

PageTransition::Type LocationBarViewGtk::GetPageTransition() const {
  return transition_;
}

void LocationBarViewGtk::AcceptInput() {
  AcceptInputWithDisposition(CURRENT_TAB);
}

void LocationBarViewGtk::AcceptInputWithDisposition(
    WindowOpenDisposition disposition) {
  location_entry_->model()->AcceptInput(disposition, false);
}

void LocationBarViewGtk::FocusLocation() {
  location_entry_->SetFocus();
  location_entry_->SelectAll(true);
}

void LocationBarViewGtk::FocusSearch() {
  location_entry_->SetFocus();
  location_entry_->SetForcedQuery();
}

void LocationBarViewGtk::UpdatePageActions() {
  // http://code.google.com/p/chromium/issues/detail?id=11973
}

void LocationBarViewGtk::SaveStateToContents(TabContents* contents) {
  // http://crbug.com/9225
}

void LocationBarViewGtk::Revert() {
  location_entry_->RevertAll();
}

gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget,
                                          GdkEventExpose* event) {
  GdkDrawable* drawable = GDK_DRAWABLE(event->window);
  GdkGC* gc = gdk_gc_new(drawable);

  GdkRectangle* alloc_rect = &hbox_->allocation;

  // The area outside of our margin, which includes the border.
  GdkRectangle inner_rect = {
      alloc_rect->x,
      alloc_rect->y + kTopMargin,
      alloc_rect->width,
      alloc_rect->height - kTopMargin - kBottomMargin};

  // Some of our calculations are a bit sloppy.  Since we draw on our parent
  // window, set a clip to make sure that we don't draw outside.
  gdk_gc_set_clip_rectangle(gc, &inner_rect);

  // Draw our 1px border.  TODO(deanm): Maybe this would be cleaner as an
  // overdrawn stroked rect with a clip to the allocation?
  gdk_gc_set_rgb_fg_color(gc, &kBorderColor);
  gdk_draw_rectangle(drawable, gc, TRUE,
                     inner_rect.x,
                     inner_rect.y,
                     inner_rect.width,
                     kBorderThickness);
  gdk_draw_rectangle(drawable, gc, TRUE,
                     inner_rect.x,
                     inner_rect.y + inner_rect.height - kBorderThickness,
                     inner_rect.width,
                     kBorderThickness);

  // Draw the background within the border.
  gdk_gc_set_rgb_fg_color(gc,
      &kBackgroundColorByLevel[toolbar_model_->GetSchemeSecurityLevel()]);
  gdk_draw_rectangle(drawable, gc, TRUE,
                     inner_rect.x,
                     inner_rect.y + kBorderThickness,
                     inner_rect.width,
                     inner_rect.height - (kBorderThickness * 2));

  g_object_unref(gc);

  return FALSE;  // Continue propagating the expose.
}

void LocationBarViewGtk::SetSecurityIcon(ToolbarModel::Icon icon) {
  gtk_widget_hide(GTK_WIDGET(security_lock_icon_image_));
  gtk_widget_hide(GTK_WIDGET(security_warning_icon_image_));
  if (icon != ToolbarModel::NO_ICON)
    gtk_widget_show(GTK_WIDGET(security_icon_align_));
  else
    gtk_widget_hide(GTK_WIDGET(security_icon_align_));
  switch (icon) {
    case ToolbarModel::LOCK_ICON:
      gtk_widget_show(GTK_WIDGET(security_lock_icon_image_));
      break;
    case ToolbarModel::WARNING_ICON:
      gtk_widget_show(GTK_WIDGET(security_warning_icon_image_));
      break;
    case ToolbarModel::NO_ICON:
      break;
    default:
      NOTREACHED();
      break;
  }
}

void LocationBarViewGtk::SetInfoText() {
  std::wstring info_text, info_tooltip;
  ToolbarModel::InfoTextType info_text_type =
      toolbar_model_->GetInfoText(&info_text, &info_tooltip);
  if (info_text_type == ToolbarModel::INFO_EV_TEXT) {
    gtk_widget_modify_fg(GTK_WIDGET(info_label_), GTK_STATE_NORMAL,
                         &kEvTextColor);
    gtk_widget_show(GTK_WIDGET(info_label_align_));
  } else {
    DCHECK_EQ(info_text_type, ToolbarModel::INFO_NO_INFO);
    DCHECK(info_text.empty());
    // Clear info_text.  Should we reset the fg here?
    gtk_widget_hide(GTK_WIDGET(info_label_align_));
  }
  gtk_label_set_text(GTK_LABEL(info_label_), WideToUTF8(info_text).c_str());
  gtk_widget_set_tooltip_text(GTK_WIDGET(info_label_),
                              WideToUTF8(info_tooltip).c_str());
}
<|endoftext|>