Use C++11 stuff in libaegisub

This commit is contained in:
Thomas Goyne 2012-11-13 06:07:39 -08:00
parent 653aa32eb2
commit 2dd1da8333
15 changed files with 147 additions and 223 deletions

View File

@ -22,13 +22,11 @@ namespace agi {
namespace charset { namespace charset {
std::string Detect(const std::string &file) { std::string Detect(const std::string &file) {
UCDetect ucd(file); return UCDetect(file).Single();
return ucd.Single();
} }
void DetectAll(const std::string& file, CharsetListDetected &list) { void DetectAll(const std::string& file, CharsetListDetected &list) {
UCDetect ucd(file); UCDetect(file).List(list);
ucd.List(list);
} }
} // namespace util } // namespace util

View File

@ -27,6 +27,8 @@
#include <iconv.h> #include <iconv.h>
#include <boost/range/algorithm.hpp>
namespace { namespace {
// ISO-6937-2 values for the first 383 codepoints // ISO-6937-2 values for the first 383 codepoints
@ -160,9 +162,8 @@ int get_iso6937(int codepoint) {
if (static_cast<size_t>(codepoint) < countof(iso6937_codepoints)) if (static_cast<size_t>(codepoint) < countof(iso6937_codepoints))
return iso6937_codepoints[codepoint]; return iso6937_codepoints[codepoint];
const extended_range *end = iso6937_extended_codepoints + countof(iso6937_extended_codepoints); auto ext = boost::lower_bound(iso6937_extended_codepoints, codepoint);
const extended_range *ext = std::lower_bound(iso6937_extended_codepoints, end, codepoint); if (ext == std::end(iso6937_extended_codepoints) || ext->codepoint != codepoint)
if (ext == end || ext->codepoint != codepoint)
return 0; return 0;
return ext->value; return ext->value;
} }

View File

@ -65,7 +65,7 @@ namespace {
# undef ADD # undef ADD
} }
std::map<const char*, const char*, ltstr>::iterator real = pretty_names.find(name); auto real = pretty_names.find(name);
if (real != pretty_names.end()) if (real != pretty_names.end())
return real->second; return real->second;
return name; return name;
@ -146,16 +146,14 @@ namespace {
{ {
const char *dstEnc = get_real_encoding_name(destEncoding); const char *dstEnc = get_real_encoding_name(destEncoding);
cd = iconv_open(dstEnc, "UTF-8"); cd = iconv_open(dstEnc, "UTF-8");
if (cd == iconv_invalid) { if (cd == iconv_invalid)
throw agi::charset::UnsupportedConversion(std::string(dstEnc) + " is not a supported character set"); throw agi::charset::UnsupportedConversion(std::string(dstEnc) + " is not a supported character set");
}
bomSize = get_bom_size(cd); bomSize = get_bom_size(cd);
iconv_close(cd); iconv_close(cd);
cd = iconv_open(dstEnc, get_real_encoding_name(sourceEncoding)); cd = iconv_open(dstEnc, get_real_encoding_name(sourceEncoding));
if (cd == iconv_invalid) { if (cd == iconv_invalid)
throw agi::charset::UnsupportedConversion(std::string("Cannot convert from ") + sourceEncoding + " to " + destEncoding); throw agi::charset::UnsupportedConversion(std::string("Cannot convert from ") + sourceEncoding + " to " + destEncoding);
}
} }
~ConverterImpl() { ~ConverterImpl() {
if (cd != iconv_invalid) iconv_close(cd); if (cd != iconv_invalid) iconv_close(cd);
@ -232,10 +230,10 @@ namespace {
if (subst) { if (subst) {
data = this; data = this;
mb_to_uc_fallback = NULL; mb_to_uc_fallback = nullptr;
mb_to_wc_fallback = NULL; mb_to_wc_fallback = nullptr;
uc_to_mb_fallback = fallback; uc_to_mb_fallback = fallback;
wc_to_mb_fallback = NULL; wc_to_mb_fallback = nullptr;
int transliterate = 1; int transliterate = 1;
iconvctl(cd, ICONV_SET_TRANSLITERATE, &transliterate); iconvctl(cd, ICONV_SET_TRANSLITERATE, &transliterate);
@ -316,7 +314,7 @@ void IconvWrapper::Convert(std::string const& source, std::string &dest) {
char *dst = buff; char *dst = buff;
size_t dstLen = sizeof(buff); size_t dstLen = sizeof(buff);
res = conv->Convert(&src, &srcLen, &dst, &dstLen); res = conv->Convert(&src, &srcLen, &dst, &dstLen);
if (res == 0) conv->Convert(NULL, NULL, &dst, &dstLen); if (res == 0) conv->Convert(nullptr, nullptr, &dst, &dstLen);
dest.append(buff, sizeof(buff) - dstLen); dest.append(buff, sizeof(buff) - dstLen);
} while (res == iconv_failed && errno == E2BIG); } while (res == iconv_failed && errno == E2BIG);
@ -341,13 +339,11 @@ void IconvWrapper::Convert(std::string const& source, std::string &dest) {
} }
size_t IconvWrapper::Convert(const char* source, size_t sourceSize, char *dest, size_t destSize) { size_t IconvWrapper::Convert(const char* source, size_t sourceSize, char *dest, size_t destSize) {
if (sourceSize == (size_t)-1) { if (sourceSize == (size_t)-1)
sourceSize = SrcStrLen(source); sourceSize = SrcStrLen(source);
}
size_t res = conv->Convert(&source, &sourceSize, &dest, &destSize); size_t res = conv->Convert(&source, &sourceSize, &dest, &destSize);
if (res == 0) res = conv->Convert(NULL, NULL, &dest, &destSize); if (res == 0) res = conv->Convert(nullptr, nullptr, &dest, &destSize);
if (res == iconv_failed) { if (res == iconv_failed) {
switch (errno) { switch (errno) {
@ -390,7 +386,7 @@ size_t IconvWrapper::RequiredBufferSize(const char* src, size_t srcLen) {
char* dst = buff; char* dst = buff;
size_t dstSize = sizeof(buff); size_t dstSize = sizeof(buff);
res = conv->Convert(&src, &srcLen, &dst, &dstSize); res = conv->Convert(&src, &srcLen, &dst, &dstSize);
conv->Convert(NULL, NULL, &dst, &dstSize); conv->Convert(nullptr, nullptr, &dst, &dstSize);
charsWritten += dst - buff; charsWritten += dst - buff;
} while (res == iconv_failed && errno == E2BIG); } while (res == iconv_failed && errno == E2BIG);

View File

@ -33,18 +33,14 @@
#include "libaegisub/json.h" #include "libaegisub/json.h"
#include "libaegisub/log.h" #include "libaegisub/log.h"
#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/map.hpp>
namespace agi { namespace agi {
namespace hotkey { namespace hotkey {
std::string Combo::Str() const { std::string Combo::Str() const {
if (key_map.empty()) return ""; return boost::algorithm::join(key_map, "-");
std::string str(key_map[0]);
str.reserve(str.size() + (key_map.size() - 1) * 2);
for (unsigned int i=1; i < key_map.size(); i++) {
str.append("-" + key_map[i]);
}
return str;
} }
std::string Combo::StrMenu() const { std::string Combo::StrMenu() const {
@ -52,8 +48,8 @@ std::string Combo::StrMenu() const {
} }
void Hotkey::ComboInsert(Combo const& combo) { void Hotkey::ComboInsert(Combo const& combo) {
str_map.insert(std::make_pair(combo.Str(), combo)); str_map.insert(make_pair(combo.Str(), combo));
cmd_map.insert(std::make_pair(combo.CmdName(), combo)); cmd_map.insert(make_pair(combo.CmdName(), combo));
} }
Hotkey::Hotkey(const std::string &file, const std::string &default_config) Hotkey::Hotkey(const std::string &file, const std::string &default_config)
@ -62,29 +58,28 @@ Hotkey::Hotkey(const std::string &file, const std::string &default_config)
LOG_D("hotkey/init") << "Generating hotkeys."; LOG_D("hotkey/init") << "Generating hotkeys.";
json::Object object(agi::json_util::file(config_file, default_config)); json::Object object(agi::json_util::file(config_file, default_config));
for (json::Object::const_iterator index(object.begin()); index != object.end(); ++index) for (auto const& hotkey_context : object)
BuildHotkey(index->first, index->second); BuildHotkey(hotkey_context.first, hotkey_context.second);
} }
void Hotkey::BuildHotkey(std::string const& context, json::Object const& hotkeys) {
for (auto const& command : hotkeys) {
const json::Array& command_hotkeys = command.second;
void Hotkey::BuildHotkey(std::string const& context, const json::Object& object) { for (auto const& hotkey : command_hotkeys) {
for (json::Object::const_iterator index(object.begin()); index != object.end(); ++index) {
const json::Array& array = index->second;
for (json::Array::const_iterator arr_index(array.begin()); arr_index != array.end(); ++arr_index) {
std::vector<std::string> keys; std::vector<std::string> keys;
try { try {
const json::Array& arr_mod = (*arr_index)["modifiers"]; const json::Array& arr_mod = hotkey["modifiers"];
keys.reserve(arr_mod.size() + 1); keys.reserve(arr_mod.size() + 1);
copy(arr_mod.begin(), arr_mod.end(), back_inserter(keys)); copy(arr_mod.begin(), arr_mod.end(), back_inserter(keys));
keys.push_back((*arr_index)["key"]); keys.push_back(hotkey["key"]);
} }
catch (json::Exception const& e) { catch (json::Exception const& e) {
LOG_E("agi/hotkey/load") << "Failed loading hotkey for command '" << index->first << "': " << e.what(); LOG_E("agi/hotkey/load") << "Failed loading hotkey for command '" << command.first << "': " << e.what();
} }
ComboInsert(Combo(context, index->first, keys)); ComboInsert(Combo(context, command.first, keys));
} }
} }
} }
@ -151,18 +146,16 @@ std::string Hotkey::GetHotkey(const std::string &context, const std::string &com
void Hotkey::Flush() { void Hotkey::Flush() {
json::Object root; json::Object root;
for (HotkeyMap::iterator index = str_map.begin(); index != str_map.end(); ++index) { for (auto const& combo : str_map | boost::adaptors::map_values) {
std::vector<std::string> const& combo_map(index->second.Get());
json::Object hotkey; json::Object hotkey;
if (combo_map.size()) { if (combo.Get().size()) {
hotkey["key"] = combo_map.back(); hotkey["key"] = combo.Get().back();
json::Array& modifiers = hotkey["modifiers"]; json::Array& modifiers = hotkey["modifiers"];
copy(combo_map.begin(), combo_map.end() - 1, std::back_inserter(modifiers)); modifiers.insert(modifiers.end(), combo.Get().begin(), combo.Get().end() - 1);
} }
json::Array& combo_array = root[index->second.Context()][index->second.CmdName()]; json::Array& combo_array = root[combo.Context()][combo.CmdName()];
combo_array.push_back(hotkey); combo_array.push_back(std::move(hotkey));
} }
io::Save file(config_file); io::Save file(config_file);
@ -173,8 +166,8 @@ void Hotkey::SetHotkeyMap(HotkeyMap const& new_map) {
cmd_map = new_map; cmd_map = new_map;
str_map.clear(); str_map.clear();
for (HotkeyMap::iterator it = cmd_map.begin(); it != cmd_map.end(); ++it) for (auto const& combo : cmd_map | boost::adaptors::map_values)
str_map.insert(make_pair(it->second.Str(), it->second)); str_map.insert(make_pair(combo.Str(), combo));
Flush(); Flush();
HotkeysChanged(); HotkeysChanged();

View File

@ -30,6 +30,9 @@
#include "libaegisub/keyframe.h" #include "libaegisub/keyframe.h"
#include "libaegisub/vfr.h" #include "libaegisub/vfr.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/range/algorithm.hpp>
namespace { namespace {
std::vector<int> agi_keyframes(std::istream &file) { std::vector<int> agi_keyframes(std::istream &file) {
double fps; double fps;
@ -37,9 +40,7 @@ std::vector<int> agi_keyframes(std::istream &file) {
file >> fps_str; file >> fps_str;
file >> fps; file >> fps;
std::vector<int> ret; return std::vector<int>(std::istream_iterator<int>(file), std::istream_iterator<int>());
copy(std::istream_iterator<int>(file), std::istream_iterator<int>(), back_inserter(ret));
return ret;
} }
std::vector<int> other_keyframes(std::istream &file, char (*func)(std::string const&)) { std::vector<int> other_keyframes(std::istream &file, char (*func)(std::string const&)) {
@ -48,12 +49,10 @@ std::vector<int> other_keyframes(std::istream &file, char (*func)(std::string co
agi::line_iterator<std::string> end; agi::line_iterator<std::string> end;
for (agi::line_iterator<std::string> iter(file); iter != end; ++iter) { for (agi::line_iterator<std::string> iter(file); iter != end; ++iter) {
char c = tolower(func(*iter)); char c = tolower(func(*iter));
if (c == 'i') { if (c == 'i')
ret.push_back(count++); ret.push_back(count++);
} else if (c == 'p' || c == 'b')
else if (c == 'p' || c == 'b') {
++count; ++count;
}
} }
return ret; return ret;
} }
@ -77,34 +76,28 @@ char x264(std::string const& line) {
if (pos == line.npos || pos + 5 >= line.size()) return 0; if (pos == line.npos || pos + 5 >= line.size()) return 0;
return line[pos + 5]; return line[pos + 5];
} }
template<int N>
bool starts_with(std::string const& str, const char (&test)[N]) {
if (str.size() < N) return false;
return std::mismatch(str.begin(), str.begin() + N - 1, test).first == str.begin() + N - 1;
}
} }
namespace agi { namespace keyframe { namespace agi { namespace keyframe {
void Save(std::string const& filename, std::vector<int> const& keyframes) { void Save(std::string const& filename, std::vector<int> const& keyframes) {
io::Save file(filename); io::Save file(filename);
std::ofstream& of = file.Get(); std::ofstream& of = file.Get();
of << "# keyframe format v1" << std::endl; of << "# keyframe format v1" << std::endl;
of << "fps " << 0 << std::endl; of << "fps " << 0 << std::endl;
copy(keyframes.begin(), keyframes.end(), std::ostream_iterator<int>(of, "\n")); boost::copy(keyframes, std::ostream_iterator<int>(of, "\n"));
} }
std::vector<int> Load(std::string const& filename) { std::vector<int> Load(std::string const& filename) {
std::auto_ptr<std::ifstream> file(io::Open(filename)); std::unique_ptr<std::ifstream> file(io::Open(filename));
std::istream &is(*file.get()); std::istream &is(*file);
std::string header; std::string header;
std::getline(is, header); getline(is, header);
if (header == "# keyframe format v1") return agi_keyframes(is); if (header == "# keyframe format v1") return agi_keyframes(is);
if (starts_with(header, "# XviD 2pass stat file")) return other_keyframes(is, xvid); if (boost::starts_with(header, "# XviD 2pass stat file")) return other_keyframes(is, xvid);
if (starts_with(header, "##map version")) return other_keyframes(is, divx); if (boost::starts_with(header, "##map version")) return other_keyframes(is, divx);
if (starts_with(header, "#options:")) return other_keyframes(is, x264); if (boost::starts_with(header, "#options:")) return other_keyframes(is, x264);
throw Error("Unknown keyframe format"); throw Error("Unknown keyframe format");
} }

View File

@ -34,6 +34,8 @@
#include "libaegisub/types.h" #include "libaegisub/types.h"
#include "libaegisub/util.h" #include "libaegisub/util.h"
#include <boost/range/algorithm.hpp>
namespace agi { namespace agi {
namespace log { namespace log {
@ -53,7 +55,7 @@ SinkMessage::SinkMessage(const char *section, Severity severity,
, func(func) , func(func)
, line(line) , line(line)
, tv(tv) , tv(tv)
, message(NULL) , message(nullptr)
, len(0) , len(0)
{ {
} }
@ -75,11 +77,7 @@ LogSink::~LogSink() {
void LogSink::log(SinkMessage *sm) { void LogSink::log(SinkMessage *sm) {
sink.push_back(sm); sink.push_back(sm);
boost::for_each(emitters, [=](Emitter *em) { em->log(sm); });
for_each(
emitters.begin(),
emitters.end(),
bind2nd(std::mem_fun(&Emitter::log), sm));
} }
void LogSink::Subscribe(Emitter *em) { void LogSink::Subscribe(Emitter *em) {
@ -139,7 +137,7 @@ JsonEmitter::~JsonEmitter() {
entry["line"] = sink[i]->line; entry["line"] = sink[i]->line;
entry["message"] = std::string(sink[i]->message, sink[i]->len); entry["message"] = std::string(sink[i]->message, sink[i]->len);
array.push_back(entry); array.push_back(std::move(entry));
} }
json::Array &timeval_open = root["timeval"]["open"]; json::Array &timeval_open = root["timeval"]["open"];

View File

@ -46,8 +46,8 @@ MRUManager::MRUManager(std::string const& config, std::string const& default_con
LOG_D("agi/mru") << "Loading MRU List"; LOG_D("agi/mru") << "Loading MRU List";
json::Object root(json_util::file(config, default_config)); json::Object root(json_util::file(config, default_config));
for (json::Object::const_iterator it(root.begin()); it != root.end(); ++it) for (auto const& it : root)
Load(it->first, it->second); Load(it.first, it.second);
} }
MRUManager::~MRUManager() { MRUManager::~MRUManager() {
@ -93,9 +93,9 @@ std::string const& MRUManager::GetEntry(std::string const& key, const size_t ent
void MRUManager::Flush() { void MRUManager::Flush() {
json::Object out; json::Object out;
for (MRUMap::const_iterator i = mru.begin(); i != mru.end(); ++i) { for (auto const& mru_map : mru) {
json::Array &array = out[i->first]; json::Array &array = out[mru_map.first];
copy(i->second.begin(), i->second.end(), std::back_inserter(array)); array.insert(array.end(), mru_map.second.begin(), mru_map.second.end());
} }
json::Writer::Write(out, io::Save(config_name).Get()); json::Writer::Write(out, io::Save(config_name).Get());
@ -106,7 +106,7 @@ void MRUManager::Flush() {
void MRUManager::Prune(std::string const& key, MRUListMap& map) const { void MRUManager::Prune(std::string const& key, MRUListMap& map) const {
size_t limit = 16u; size_t limit = 16u;
if (options) { if (options) {
std::map<const std::string, std::string>::const_iterator it = option_names.find(key); auto it = option_names.find(key);
if (it != option_names.end()) if (it != option_names.end())
limit = (size_t)options->Get(it->second)->GetInt(); limit = (size_t)options->Get(it->second)->GetInt();
} }

View File

@ -38,6 +38,8 @@
#include "option_visit.h" #include "option_visit.h"
#include <boost/range/adaptor/map.hpp>
namespace { namespace {
/// @brief Write an option to a json object /// @brief Write an option to a json object
/// @param[out] obj Parent object /// @param[out] obj Parent object
@ -50,12 +52,8 @@ namespace {
assert(obj.find(path) == obj.end()); assert(obj.find(path) == obj.end());
obj[path] = value; obj[path] = value;
} }
else { else
put_option( put_option(obj[path.substr(0, pos)], path.substr(pos + 1), value);
obj[path.substr(0, pos)],
path.substr(pos + 1),
value);
}
} }
template<class T> template<class T>
@ -80,13 +78,11 @@ Options::Options(const std::string &file, const std::string& default_config, con
} }
Options::~Options() { Options::~Options() {
if ((setting & FLUSH_SKIP) != FLUSH_SKIP) { if ((setting & FLUSH_SKIP) != FLUSH_SKIP)
Flush(); Flush();
}
for (OptionValueMap::iterator i = values.begin(); i != values.end(); i++) { for (auto option_value : values | boost::adaptors::map_values)
delete i->second; delete option_value;
}
} }
void Options::ConfigNext(std::istream& stream) { void Options::ConfigNext(std::istream& stream) {
@ -94,7 +90,7 @@ void Options::ConfigNext(std::istream& stream) {
} }
void Options::ConfigUser() { void Options::ConfigUser() {
std::auto_ptr<std::istream> stream; std::unique_ptr<std::istream> stream;
try { try {
stream.reset(agi::io::Open(config_file)); stream.reset(agi::io::Open(config_file));
@ -125,9 +121,8 @@ void Options::LoadConfig(std::istream& stream, bool ignore_errors) {
} }
OptionValue* Options::Get(const std::string &name) { OptionValue* Options::Get(const std::string &name) {
OptionValueMap::iterator index; auto index = values.find(name);
if (index != values.end())
if ((index = values.find(name)) != values.end())
return index->second; return index->second;
LOG_E("option/get") << "agi::Options::Get Option not found: (" << name << ")"; LOG_E("option/get") << "agi::Options::Get Option not found: (" << name << ")";
@ -137,46 +132,46 @@ OptionValue* Options::Get(const std::string &name) {
void Options::Flush() { void Options::Flush() {
json::Object obj_out; json::Object obj_out;
for (OptionValueMap::const_iterator i = values.begin(); i != values.end(); ++i) { for (auto const& ov : values) {
switch (i->second->GetType()) { switch (ov.second->GetType()) {
case OptionValue::Type_String: case OptionValue::Type_String:
put_option(obj_out, i->first, i->second->GetString()); put_option(obj_out, ov.first, ov.second->GetString());
break; break;
case OptionValue::Type_Int: case OptionValue::Type_Int:
put_option(obj_out, i->first, i->second->GetInt()); put_option(obj_out, ov.first, ov.second->GetInt());
break; break;
case OptionValue::Type_Double: case OptionValue::Type_Double:
put_option(obj_out, i->first, i->second->GetDouble()); put_option(obj_out, ov.first, ov.second->GetDouble());
break; break;
case OptionValue::Type_Color: case OptionValue::Type_Color:
put_option(obj_out, i->first, i->second->GetColor().GetRgbFormatted()); put_option(obj_out, ov.first, ov.second->GetColor().GetRgbFormatted());
break; break;
case OptionValue::Type_Bool: case OptionValue::Type_Bool:
put_option(obj_out, i->first, i->second->GetBool()); put_option(obj_out, ov.first, ov.second->GetBool());
break; break;
case OptionValue::Type_List_String: case OptionValue::Type_List_String:
put_array(obj_out, i->first, "string", i->second->GetListString()); put_array(obj_out, ov.first, "string", ov.second->GetListString());
break; break;
case OptionValue::Type_List_Int: case OptionValue::Type_List_Int:
put_array(obj_out, i->first, "int", i->second->GetListInt()); put_array(obj_out, ov.first, "int", ov.second->GetListInt());
break; break;
case OptionValue::Type_List_Double: case OptionValue::Type_List_Double:
put_array(obj_out, i->first, "double", i->second->GetListDouble()); put_array(obj_out, ov.first, "double", ov.second->GetListDouble());
break; break;
case OptionValue::Type_List_Color: case OptionValue::Type_List_Color:
put_array(obj_out, i->first, "color", i->second->GetListColor()); put_array(obj_out, ov.first, "color", ov.second->GetListColor());
break; break;
case OptionValue::Type_List_Bool: case OptionValue::Type_List_Bool:
put_array(obj_out, i->first, "bool", i->second->GetListBool()); put_array(obj_out, ov.first, "bool", ov.second->GetListBool());
break; break;
} }
} }

View File

@ -50,14 +50,12 @@ void ConfigVisitor::Error(const char *message) {
} }
void ConfigVisitor::Visit(const json::Object& object) { void ConfigVisitor::Visit(const json::Object& object) {
json::Object::const_iterator index(object.begin()), index_end(object.end());
if (!name.empty()) if (!name.empty())
name += "/"; name += "/";
for (; index != index_end; ++index) { for (auto const& obj : object) {
ConfigVisitor config_visitor(values, name + index->first, ignore_errors, replace); ConfigVisitor config_visitor(values, name + obj.first, ignore_errors, replace);
index->second.Accept(config_visitor); obj.second.Accept(config_visitor);
} }
} }
@ -66,9 +64,7 @@ OptionValue *ConfigVisitor::ReadArray(json::Array const& src, std::string const&
std::vector<ValueType> arr; std::vector<ValueType> arr;
arr.reserve(src.size()); arr.reserve(src.size());
for (json::Array::const_iterator it = src.begin(); it != src.end(); ++it) { for (json::Object const& obj : src) {
json::Object const& obj = *it;
if (obj.size() != 1) { if (obj.size() != 1) {
Error<OptionJsonValueArray>("Invalid array member"); Error<OptionJsonValueArray>("Invalid array member");
return 0; return 0;

View File

@ -22,22 +22,15 @@
#include "libaegisub/io.h" #include "libaegisub/io.h"
#include "libaegisub/line_iterator.h" #include "libaegisub/line_iterator.h"
#include <boost/algorithm/string.hpp>
#include <boost/phoenix/operator/comparison.hpp>
#include <boost/phoenix/core/argument.hpp>
#ifndef LAGI_PRE #ifndef LAGI_PRE
#include <cstdlib> #include <cstdlib>
#endif #endif
template<class String, class Char, class Container> using boost::phoenix::placeholders::_1;
static void split(String const& str, Char sep, Container *out) {
typename String::size_type pos, prev = 0;
out->reserve(2);
while ((pos = str.find(sep, prev)) != String::npos) {
if (pos > prev)
out->push_back(str.substr(prev, pos - prev));
prev = pos + 1;
}
if (prev < str.size())
out->push_back(str.substr(prev));
}
namespace agi { namespace agi {
@ -54,10 +47,9 @@ Thesaurus::Thesaurus(std::string const& dat_path, std::string const& idx_path)
// Read the list of words and file offsets for those words // Read the list of words and file offsets for those words
for (line_iterator<std::string> iter(*idx, encoding_name), end; iter != end; ++iter) { for (line_iterator<std::string> iter(*idx, encoding_name), end; iter != end; ++iter) {
std::vector<std::string> chunks; std::vector<std::string> chunks;
split(*iter, '|', &chunks); boost::split(chunks, *iter, _1 == '|');
if (chunks.size() == 2) { if (chunks.size() == 2)
offsets[chunks[0]] = atoi(chunks[1].c_str()); offsets[chunks[0]] = atoi(chunks[1].c_str());
}
} }
conv.reset(new charset::IconvWrapper(encoding_name.c_str(), "utf-8")); conv.reset(new charset::IconvWrapper(encoding_name.c_str(), "utf-8"));
@ -67,9 +59,10 @@ Thesaurus::~Thesaurus() { }
void Thesaurus::Lookup(std::string const& word, std::vector<Entry> *out) { void Thesaurus::Lookup(std::string const& word, std::vector<Entry> *out) {
out->clear(); out->clear();
if (!dat.get()) return;
std::map<std::string, int>::const_iterator it = offsets.find(word); std::map<std::string, int>::const_iterator it = offsets.find(word);
if (!dat.get() || it == offsets.end()) return; if (it == offsets.end()) return;
dat->seekg(it->second, std::ios::beg); dat->seekg(it->second, std::ios::beg);
if (!dat->good()) return; if (!dat->good()) return;
@ -78,7 +71,7 @@ void Thesaurus::Lookup(std::string const& word, std::vector<Entry> *out) {
std::string temp; std::string temp;
getline(*dat, temp); getline(*dat, temp);
std::vector<std::string> header; std::vector<std::string> header;
split(conv->Convert(temp), '|', &header); boost::split(header, conv->Convert(temp), _1 == '|');
if (header.size() != 2) return; if (header.size() != 2) return;
int meanings = atoi(header[1].c_str()); int meanings = atoi(header[1].c_str());
@ -86,7 +79,7 @@ void Thesaurus::Lookup(std::string const& word, std::vector<Entry> *out) {
for (int i = 0; i < meanings; ++i) { for (int i = 0; i < meanings; ++i) {
std::vector<std::string> line; std::vector<std::string> line;
getline(*dat, temp); getline(*dat, temp);
split(conv->Convert(temp), '|', &line); boost::split(line, conv->Convert(temp), _1 == '|');
// The "definition" is just the part of speech plus the word it's // The "definition" is just the part of speech plus the word it's
// giving synonyms for (which may not be the passed word) // giving synonyms for (which may not be the passed word)

View File

@ -24,24 +24,20 @@
#include <locale> #include <locale>
#endif #endif
#include "libaegisub/util.h" #include "libaegisub/util.h"
#include <boost/algorithm/string/case_conv.hpp>
namespace agi { namespace agi {
namespace util { namespace util {
void str_lower(std::string &str) { void str_lower(std::string &str) {
std::locale loc; boost::to_lower(str);
for (size_t i=0; i < str.length(); ++i) {
str[i] = std::tolower(str[i], loc);
}
} }
int strtoi(std::string &str) { int strtoi(std::string &str) {
errno = 0; errno = 0;
long l = strtol(str.c_str(), NULL, 10); long l = strtol(str.c_str(), nullptr, 10);
if ((errno == ERANGE) || (l < INT_MIN) || (l > INT_MAX)) if ((errno == ERANGE) || (l < INT_MIN) || (l > INT_MAX))
return 0; return 0;
@ -49,6 +45,5 @@ int strtoi(std::string &str) {
return (int)l; return (int)l;
} }
} // namespace util } // namespace util
} // namespace agi } // namespace agi

View File

@ -32,6 +32,8 @@
#include "libaegisub/line_iterator.h" #include "libaegisub/line_iterator.h"
#include "libaegisub/scoped_ptr.h" #include "libaegisub/scoped_ptr.h"
#include <boost/range/algorithm.hpp>
namespace std { namespace std {
template<> void swap(agi::vfr::Framerate &lft, agi::vfr::Framerate &rgt) { template<> void swap(agi::vfr::Framerate &lft, agi::vfr::Framerate &rgt) {
lft.swap(rgt); lft.swap(rgt);
@ -43,27 +45,20 @@ static const int64_t default_denominator = 1000000000;
namespace agi { namespace agi {
namespace vfr { namespace vfr {
static int is_increasing(int prev, int cur) {
if (prev > cur)
throw UnorderedTimecodes("Timecodes are out of order");
return cur;
}
/// @brief Verify that timecodes monotonically increase /// @brief Verify that timecodes monotonically increase
/// @param timecodes List of timecodes to check /// @param timecodes List of timecodes to check
static void validate_timecodes(std::vector<int> const& timecodes) { static void validate_timecodes(std::vector<int> const& timecodes) {
if (timecodes.size() <= 1) { if (timecodes.size() <= 1)
throw TooFewTimecodes("Must have at least two timecodes to do anything useful"); throw TooFewTimecodes("Must have at least two timecodes to do anything useful");
} if (!is_sorted(timecodes.begin(), timecodes.end()))
std::accumulate(timecodes.begin()+1, timecodes.end(), timecodes.front(), is_increasing); throw UnorderedTimecodes("Timecodes are out of order");
} }
/// @brief Shift timecodes so that frame 0 starts at time 0 /// @brief Shift timecodes so that frame 0 starts at time 0
/// @param timecodes List of timecodes to normalize /// @param timecodes List of timecodes to normalize
static void normalize_timecodes(std::vector<int> &timecodes) { static void normalize_timecodes(std::vector<int> &timecodes) {
if (int front = timecodes.front()) { if (int front = timecodes.front())
std::transform(timecodes.begin(), timecodes.end(), timecodes.begin(), std::bind2nd(std::minus<int>(), front)); boost::for_each(timecodes, [=](int &tc) { tc -= front; });
}
} }
// A "start,end,fps" line in a v1 timecode file // A "start,end,fps" line in a v1 timecode file
@ -74,7 +69,8 @@ struct TimecodeRange {
bool operator<(TimecodeRange const& cmp) const { bool operator<(TimecodeRange const& cmp) const {
return start < cmp.start; return start < cmp.start;
} }
TimecodeRange() : fps(0.) { } TimecodeRange(int start=0, int end=0, double fps=0.)
: start(start), end(end), fps(fps) { }
}; };
/// @brief Parse a single line of a v1 timecode file /// @brief Parse a single line of a v1 timecode file
@ -87,57 +83,38 @@ static TimecodeRange v1_parse_line(std::string const& str) {
TimecodeRange range; TimecodeRange range;
char comma1, comma2; char comma1, comma2;
ss >> range.start >> comma1 >> range.end >> comma2 >> range.fps; ss >> range.start >> comma1 >> range.end >> comma2 >> range.fps;
if (ss.fail() || comma1 != ',' || comma2 != ',' || !ss.eof()) { if (ss.fail() || comma1 != ',' || comma2 != ',' || !ss.eof())
throw MalformedLine(str); throw MalformedLine(str);
} if (range.start < 0 || range.end < 0)
if (range.start < 0 || range.end < 0) {
throw UnorderedTimecodes("Cannot specify frame rate for negative frames."); throw UnorderedTimecodes("Cannot specify frame rate for negative frames.");
} if (range.end < range.start)
if (range.end < range.start) {
throw UnorderedTimecodes("End frame must be greater than or equal to start frame"); throw UnorderedTimecodes("End frame must be greater than or equal to start frame");
} if (range.fps <= 0.)
if (range.fps <= 0.) {
throw BadFPS("FPS must be greater than zero"); throw BadFPS("FPS must be greater than zero");
} if (range.fps > 1000.)
if (range.fps > 1000.) {
// This is our limitation, not mkvmerge's // This is our limitation, not mkvmerge's
// mkvmerge uses nanoseconds internally // mkvmerge uses nanoseconds internally
throw BadFPS("FPS must be at most 1000"); throw BadFPS("FPS must be at most 1000");
}
return range; return range;
} }
/// @brief Is the timecode range a comment line?
static bool v1_invalid_timecode(TimecodeRange const& range) {
return range.fps == 0.;
}
/// @brief Generate override ranges for all frames with assumed fpses /// @brief Generate override ranges for all frames with assumed fpses
/// @param ranges List with ranges which is mutated /// @param ranges List with ranges which is mutated
/// @param fps Assumed fps to use for gaps /// @param fps Assumed fps to use for gaps
static void v1_fill_range_gaps(std::list<TimecodeRange> &ranges, double fps) { static void v1_fill_range_gaps(std::list<TimecodeRange> &ranges, double fps) {
// Range for frames between start and first override // Range for frames between start and first override
if (ranges.empty() || ranges.front().start > 0) { if (ranges.empty() || ranges.front().start > 0)
TimecodeRange range; ranges.emplace_front(0, ranges.empty() ? 0 : ranges.front().start - 1, fps);
range.fps = fps;
range.start = 0;
range.end = ranges.empty() ? 0 : ranges.front().start - 1;
ranges.push_front(range);
}
std::list<TimecodeRange>::iterator cur = ++ranges.begin(); std::list<TimecodeRange>::iterator cur = ++ranges.begin();
std::list<TimecodeRange>::iterator prev = ranges.begin(); std::list<TimecodeRange>::iterator prev = ranges.begin();
for (; cur != ranges.end(); ++cur, ++prev) { for (; cur != ranges.end(); ++cur, ++prev) {
if (prev->end >= cur->start) { if (prev->end >= cur->start)
// mkvmerge allows overlapping timecode ranges, but does completely // mkvmerge allows overlapping timecode ranges, but does completely
// broken things with them // broken things with them
throw UnorderedTimecodes("Override ranges must not overlap"); throw UnorderedTimecodes("Override ranges must not overlap");
}
if (prev->end + 1 < cur->start) { if (prev->end + 1 < cur->start) {
TimecodeRange range; ranges.emplace(cur, prev->end + 1, cur->start -1, fps);
range.fps = fps;
range.start = prev->end + 1;
range.end = cur->start - 1;
ranges.insert(cur, range);
++prev; ++prev;
} }
} }
@ -150,24 +127,23 @@ static void v1_fill_range_gaps(std::list<TimecodeRange> &ranges, double fps) {
/// @param[out] last Unrounded time of the last frame /// @param[out] last Unrounded time of the last frame
/// @return Assumed fps times one million /// @return Assumed fps times one million
static int64_t v1_parse(line_iterator<std::string> file, std::string line, std::vector<int> &timecodes, int64_t &last) { static int64_t v1_parse(line_iterator<std::string> file, std::string line, std::vector<int> &timecodes, int64_t &last) {
using namespace std;
double fps = atof(line.substr(7).c_str()); double fps = atof(line.substr(7).c_str());
if (fps <= 0.) throw BadFPS("Assumed FPS must be greater than zero"); if (fps <= 0.) throw BadFPS("Assumed FPS must be greater than zero");
if (fps > 1000.) throw BadFPS("Assumed FPS must not be greater than 1000"); if (fps > 1000.) throw BadFPS("Assumed FPS must not be greater than 1000");
list<TimecodeRange> ranges; std::list<TimecodeRange> ranges;
transform(file, line_iterator<string>(), back_inserter(ranges), v1_parse_line); transform(file, line_iterator<std::string>(), back_inserter(ranges), v1_parse_line);
ranges.erase(remove_if(ranges.begin(), ranges.end(), v1_invalid_timecode), ranges.end()); ranges.erase(boost::remove_if(ranges, [](TimecodeRange const& r) { return r.fps == 0; }), ranges.end());
ranges.sort(); ranges.sort();
v1_fill_range_gaps(ranges, fps); v1_fill_range_gaps(ranges, fps);
timecodes.reserve(ranges.back().end); timecodes.reserve(ranges.back().end);
double time = 0.; double time = 0.;
for (list<TimecodeRange>::iterator cur = ranges.begin(); cur != ranges.end(); ++cur) { for (auto const& range : ranges) {
for (int frame = cur->start; frame <= cur->end; frame++) { for (int frame = range.start; frame <= range.end; ++frame) {
timecodes.push_back(int(time + .5)); timecodes.push_back(int(time + .5));
time += 1000. / cur->fps; time += 1000. / range.fps;
} }
} }
timecodes.push_back(int(time + .5)); timecodes.push_back(int(time + .5));
@ -229,20 +205,18 @@ Framerate::Framerate(std::string const& filename)
: denominator(default_denominator) : denominator(default_denominator)
, numerator(0) , numerator(0)
{ {
using namespace std; scoped_ptr<std::ifstream> file(agi::io::Open(filename));
scoped_ptr<ifstream> file(agi::io::Open(filename)); std::string encoding = agi::charset::Detect(filename);
string encoding = agi::charset::Detect(filename); std::string line = *line_iterator<std::string>(*file, encoding);
string line = *line_iterator<string>(*file, encoding);
if (line == "# timecode format v2") { if (line == "# timecode format v2") {
copy(line_iterator<int>(*file, encoding), line_iterator<int>(), back_inserter(timecodes)); copy(line_iterator<int>(*file, encoding), line_iterator<int>(), back_inserter(timecodes));
SetFromTimecodes(); SetFromTimecodes();
return; return;
} }
if (line == "# timecode format v1" || line.substr(0, 7) == "Assume ") { if (line == "# timecode format v1" || line.substr(0, 7) == "Assume ") {
if (line[0] == '#') { if (line[0] == '#')
line = *line_iterator<string>(*file, encoding); line = *line_iterator<std::string>(*file, encoding);
} numerator = v1_parse(line_iterator<std::string>(*file, encoding), line, timecodes, last);
numerator = v1_parse(line_iterator<string>(*file, encoding), line, timecodes, last);
return; return;
} }
@ -254,10 +228,9 @@ void Framerate::Save(std::string const& filename, int length) const {
std::ofstream &out = file.Get(); std::ofstream &out = file.Get();
out << "# timecode format v2\n"; out << "# timecode format v2\n";
std::copy(timecodes.begin(), timecodes.end(), std::ostream_iterator<int>(out, "\n")); boost::copy(timecodes, std::ostream_iterator<int>(out, "\n"));
for (int written = (int)timecodes.size(); written < length; ++written) { for (int written = (int)timecodes.size(); written < length; ++written)
out << TimeAtFrame(written) << std::endl; out << TimeAtFrame(written) << std::endl;
}
} }
int Framerate::FrameAtTime(int ms, Time type) const { int Framerate::FrameAtTime(int ms, Time type) const {
@ -274,12 +247,10 @@ int Framerate::FrameAtTime(int ms, Time type) const {
// Combining these allows us to easily calculate START and END in terms of // Combining these allows us to easily calculate START and END in terms of
// EXACT // EXACT
if (type == START) { if (type == START)
return FrameAtTime(ms - 1) + 1; return FrameAtTime(ms - 1) + 1;
} if (type == END)
if (type == END) {
return FrameAtTime(ms - 1); return FrameAtTime(ms - 1);
}
if (ms < 0) if (ms < 0)
return int((ms * numerator / denominator - 999) / 1000); return int((ms * numerator / denominator - 999) / 1000);

View File

@ -115,7 +115,7 @@ namespace detail {
/// Used by the signal when the signal wishes to end a connection (such /// Used by the signal when the signal wishes to end a connection (such
/// as if the signal is being destroyed while slots are still connected /// as if the signal is being destroyed while slots are still connected
/// to it) /// to it)
void DisconnectToken(ConnectionToken *tok) { tok->signal = NULL; } void DisconnectToken(ConnectionToken *tok) { tok->signal = nullptr; }
/// @brief Has a token been claimed by a scoped connection object? /// @brief Has a token been claimed by a scoped connection object?
bool TokenClaimed(ConnectionToken *tok) { return tok->claimed; } bool TokenClaimed(ConnectionToken *tok) { return tok->claimed; }
@ -129,7 +129,7 @@ namespace detail {
inline void ConnectionToken::Disconnect() { inline void ConnectionToken::Disconnect() {
if (signal) signal->Disconnect(this); if (signal) signal->Disconnect(this);
signal = NULL; signal = nullptr;
} }
/// @brief Templated common code for signals /// @brief Templated common code for signals
@ -176,7 +176,7 @@ namespace detail {
} }
#define SIGNALS_H_FOR_EACH_SIGNAL(...) \ #define SIGNALS_H_FOR_EACH_SIGNAL(...) \
for (typename super::SlotMap::iterator cur = slots.begin(); cur != slots.end();) { \ for (auto cur = slots.begin(); cur != slots.end();) { \
if (Blocked(cur->first)) \ if (Blocked(cur->first)) \
++cur; \ ++cur; \
else \ else \
@ -261,16 +261,11 @@ class Signal<void> : public detail::SignalBaseImpl<std::function<void ()> > {
using super::slots; using super::slots;
public: public:
Signal() { } Signal() { }
// Work around compilters that can't tell this is a template context due to it
// being fully specified, making typename invalid here.
#define typename
/// @brief Trigger this signal /// @brief Trigger this signal
/// ///
/// The order in which connected slots are called is undefined and should /// The order in which connected slots are called is undefined and should
/// not be relied on /// not be relied on
void operator()() { SIGNALS_H_FOR_EACH_SIGNAL() } void operator()() { SIGNALS_H_FOR_EACH_SIGNAL() }
#undef typename
}; };
#undef SIGNALS_H_FOR_EACH_SIGNAL #undef SIGNALS_H_FOR_EACH_SIGNAL

View File

@ -105,7 +105,7 @@ void Check(const std::string &file, acs::Type type) {
SECURITY_INFORMATION info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; SECURITY_INFORMATION info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
DWORD len = 0; DWORD len = 0;
GetFileSecurity(wfile.c_str(), info, NULL, 0, &len); GetFileSecurity(wfile.c_str(), info, nullptr, 0, &len);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
LOG_W("acs/check") << "GetFileSecurity: fatal: " << util::ErrorString(GetLastError()); LOG_W("acs/check") << "GetFileSecurity: fatal: " << util::ErrorString(GetLastError());

View File

@ -60,9 +60,9 @@ void Rename(const std::string& from, const std::string& to) {
} }
std::string ErrorString(DWORD error) { std::string ErrorString(DWORD error) {
LPWSTR lpstr = NULL; LPWSTR lpstr = nullptr;
if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, reinterpret_cast<LPWSTR>(&lpstr), 0, NULL) == 0) { if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error, 0, reinterpret_cast<LPWSTR>(&lpstr), 0, nullptr) == 0) {
/// @todo Return the actual 'unknown error' string from windows. /// @todo Return the actual 'unknown error' string from windows.
return "Unknown Error"; return "Unknown Error";
} }