Beispiel #1
0
	void load_resolutions(const config& cfg)
	{
		config::const_child_itors itors = cfg.child_range("resolution");
		FOREACH(const AUTO & resolution, itors)
		{
			resolutions.push_back(new T(resolution));
		}
Beispiel #2
0
void item_palette::setup(const config& cfg)
{

	for (const config& group : cfg.child_range("item_group")) {

		groups_.push_back(item_group(group));

		for (const config& item : group.child_range("item")) {

			item_map_.insert(std::pair<std::string, overlay>(item["id"], overlay(item)));
			group_map_[group["id"]].push_back(item["id"]);
			if (!group["core"].to_bool(false))
				non_core_items_.insert(item["id"]);
		}
		nmax_items_ = std::max(nmax_items_, group_map_[group["id"]].size());
	}

	select_fg_item("anvil");
	select_bg_item("altar");

	// Set the default group
	set_group("items");

	if(active_group().empty()) {
		ERR_ED << "No items found." << std::endl;
	}
}
Beispiel #3
0
static void verify(const unit_map& units, const config& cfg) {
	std::stringstream errbuf;
	LOG_REPLAY << "verifying unit structure...\n";

	const size_t nunits = cfg["num_units"].to_size_t();
	if(nunits != units.size()) {
		errbuf << "SYNC VERIFICATION FAILED: number of units from data source differ: "
			   << nunits << " according to data source. " << units.size() << " locally\n";

		std::set<map_location> locs;
		BOOST_FOREACH(const config &u, cfg.child_range("unit"))
		{
			const map_location loc(u, resources::gamedata);
			locs.insert(loc);

			if(units.count(loc) == 0) {
				errbuf << "data source says there is a unit at "
					   << loc << " but none found locally\n";
			}
		}

		for(unit_map::const_iterator j = units.begin(); j != units.end(); ++j) {
			if (locs.count(j->get_location()) == 0) {
				errbuf << "local unit at " << j->get_location()
					   << " but none in data source\n";
			}
		}
		replay::process_error(errbuf.str());
		errbuf.clear();
	}
void editor_controller::init_tods(const config& game_config)
{
	BOOST_FOREACH(const config &schedule, game_config.child_range("editor_times")) {

		const std::string& schedule_id = schedule["id"];
		const std::string& schedule_name = schedule["name"];
		if (schedule_id.empty()) {
			ERR_ED << "Missing ID attribute in a TOD Schedule.\n";
			continue;
		}

		tods_map::iterator times = tods_.find(schedule_id);
		if (times == tods_.end()) {
			std::pair<tods_map::iterator, bool> new_times =
					tods_.insert( std::pair<std::string, std::pair<std::string, std::vector<time_of_day> > >
			(schedule_id, std::pair<std::string, std::vector<time_of_day> >(schedule_name, std::vector<time_of_day>())) );
			times = new_times.first;
		} else {
			ERR_ED << "Duplicate TOD Schedule ids.\n";
			continue;
		}

		BOOST_FOREACH(const config &time, schedule.child_range("time")) {
			times->second.second.push_back(time_of_day(time));
		}

	}

	if (tods_.empty()) {
		ERR_ED << "No editor time-of-day defined\n";
	}
}
Beispiel #5
0
void game_state::place_sides_in_preferred_locations(const config& level)
{
	std::vector<placing_info> placings;

	int num_pos = board_.map().num_valid_starting_positions();

	int side_num = 1;
	BOOST_FOREACH(const config &side, level.child_range("side"))
	{
		for(int p = 1; p <= num_pos; ++p) {
			const map_location& pos = board_.map().starting_position(p);
			int score = placing_score(side, board_.map(), pos);
			placing_info obj;
			obj.side = side_num;
			obj.score = score;
			obj.pos = pos;
			placings.push_back(obj);
		}
		++side_num;
	}

	std::stable_sort(placings.begin(),placings.end());
	std::set<int> placed;
	std::set<map_location> positions_taken;

	for (std::vector<placing_info>::const_iterator i = placings.begin(); i != placings.end() && int(placed.size()) != side_num - 1; ++i) {
		if(placed.count(i->side) == 0 && positions_taken.count(i->pos) == 0) {
			placed.insert(i->side);
			positions_taken.insert(i->pos);
			board_.map_->set_starting_position(i->side,i->pos);
			LOG_NG << "placing side " << i->side << " at " << i->pos << std::endl;
		}
	}
}
unit_race::unit_race(const config& cfg) :
		id_(cfg["id"]),
		plural_name_(cfg["plural_name"].t_str()),
		description_(cfg["description"].t_str()),
		ntraits_(cfg["num_traits"]),
		chain_size_(cfg["markov_chain_size"]),
		traits_(cfg.child_range("trait")),
		global_traits_(!cfg["ignore_global_traits"].to_bool())

{
	if (id_.empty()) {
		lg::wml_error << "[race] '" << cfg["name"] << "' is missing an id field.";
	}
	if (plural_name_.empty()) {
		lg::wml_error << "[race] '" << cfg["name"] << "' is missing a plural_name field.";
		plural_name_ = (cfg["name"]);
	}
	// use "name" if "male_name" or "female_name" aren't available
	name_[MALE] = cfg["male_name"];
	if(name_[MALE].empty()) {
		name_[MALE] = (cfg["name"]);
	}
	name_[FEMALE] = cfg["female_name"];
	if(name_[FEMALE].empty()) {
		name_[FEMALE] = (cfg["name"]);
	}

	if(chain_size_ <= 0)
		chain_size_ = 2;

	//std::vector<std::string> names = ;
	next_[MALE] = markov_prefixes(utils::split(cfg["male_names"]), chain_size_);
	next_[FEMALE] = markov_prefixes(utils::split(cfg["female_names"]), chain_size_);
}
Beispiel #7
0
static std::vector<std::map<std::string, string_map>> parse_list_data(const config& data, const unsigned int req_cols)
{
	std::vector<std::map<std::string, string_map>> list_data;
	for(const auto & row : data.child_range("row"))
	{
		auto cols = row.child_range("column");
		VALIDATE(static_cast<unsigned>(cols.size()) == req_cols, _("'list_data' must have the same number of columns as the 'list_definition'."));

		for(const auto & c : cols)
		{
			list_data.emplace_back();
			for(const auto & i : c.attribute_range())
			{
				list_data.back()[""][i.first] = i.second;
			}
			for(const auto& w : c.child_range("widget"))
			{
				VALIDATE(w.has_attribute("id"), missing_mandatory_wml_key("[list_data][row][column][widget]", "id"));
				for(const auto& i : w.attribute_range()) {
					list_data.back()[w["id"]][i.first] = i.second;
				}
			}
		}
	}
	return list_data;
}
Beispiel #8
0
void addon_info::read(const config& cfg)
{
	this->id = cfg["name"].str();
	this->title = cfg["title"].str();
	this->description = cfg["description"].str();
	this->icon = cfg["icon"].str();
	this->version = cfg["version"].str();
	this->author = cfg["author"].str();
	this->size = cfg["size"];
	this->downloads = cfg["downloads"];
	this->uploads = cfg["uploads"];
	this->type = get_addon_type(cfg["type"].str());

	const config::const_child_itors& locales_as_configs = cfg.child_range("translation");

	for(const config& locale : locales_as_configs) {
		this->locales.push_back(locale["language"].str());
	}

	this->core = cfg["core"].str();
	this->depends = utils::split(cfg["dependencies"].str());
	this->feedback_url = cfg["feedback_url"].str();

	this->updated = cfg["timestamp"].to_time_t();
	this->created = cfg["original_timestamp"].to_time_t();
}
void editor_controller::init_mouse_actions(const config& game_config)
{
	mouse_actions_.insert(std::make_pair(hotkey::HOTKEY_EDITOR_TOOL_PAINT,
		new mouse_action_paint(foreground_terrain_, background_terrain_, &brush_, key_)));
	mouse_actions_.insert(std::make_pair(hotkey::HOTKEY_EDITOR_TOOL_FILL,
		new mouse_action_fill(foreground_terrain_, background_terrain_, key_)));
	mouse_actions_.insert(std::make_pair(hotkey::HOTKEY_EDITOR_TOOL_SELECT,
		new mouse_action_select(&brush_, key_)));
	mouse_actions_.insert(std::make_pair(hotkey::HOTKEY_EDITOR_TOOL_STARTING_POSITION,
		new mouse_action_starting_position(key_)));
	mouse_actions_.insert(std::make_pair(hotkey::HOTKEY_EDITOR_PASTE,
		new mouse_action_paste(clipboard_, key_)));
	foreach (const theme::menu& menu, gui().get_theme().menus()) {
		if (menu.items().size() == 1) {
			hotkey::HOTKEY_COMMAND hk = hotkey::get_hotkey(menu.items().front()).get_id();
			mouse_action_map::iterator i = mouse_actions_.find(hk);
			if (i != mouse_actions_.end()) {
				i->second->set_toolbar_button(&menu);
			}
		}
	}
	foreach (const config &c, game_config.child_range("editor_tool_hint")) {
		mouse_action_map::iterator i =
			mouse_actions_.find(hotkey::get_hotkey(c["id"]).get_id());
		if (i != mouse_actions_.end()) {
			mouse_action_hints_.insert(std::make_pair(i->first, c["text"]));
		}
	}
}
void terrain_palette::setup(const config& cfg)
{
	// Get the available terrains temporary in items
	t_translation::t_list items = map().get_terrain_list();

	//move "invalid" items to the end
	std::stable_partition(items.begin(), items.end(), is_valid_terrain);

	// Get the available groups and add them to the structure
	std::set<std::string> group_names;
	BOOST_FOREACH(const config &group, cfg.child_range("editor_group"))
	{
		if (group_names.find(group["id"]) == group_names.end()) {

			config cfg;
			cfg["id"] = group["id"];
			cfg["name"] = group["name"];

			cfg["icon"] = "icons/terrain/terrain_" + group["icon"].str();
			cfg["core"] = group["core"];
			groups_.push_back(item_group(cfg));

			group_names.insert(groups_.back().id);
		}
	}

	std::map<std::string, item_group*> id_to_group;
	BOOST_FOREACH(item_group& group, groups_) {
		id_to_group.insert(std::make_pair(group.id, &group));
	}
Beispiel #11
0
/**
 * Read the undo_list from the provided config.
 * Currently, this is only used when the undo_list is empty, but in theory
 * it could be used to append the config to the current data.
 */
void undo_list::read(const config & cfg)
{
	// Merge header data.
	side_ = cfg["side"].to_int(side_);
	committed_actions_ = committed_actions_ || cfg["committed"].to_bool();

	// Build the undo stack.
	for (const config & child : cfg.child_range("undo")) {
		try {
			undo_action_base * action = create_action(child);
			if ( action ) {
				undos_.push_back(action);
			}
		} catch (bad_lexical_cast &) {
			ERR_NG << "Error when parsing undo list from config: bad lexical cast." << std::endl;
			ERR_NG << "config was: " << child.debug() << std::endl;
			ERR_NG << "Skipping this undo action..." << std::endl;
		} catch (config::error& e) {
			ERR_NG << "Error when parsing undo list from config: " << e.what() << std::endl;
			ERR_NG << "config was: " << child.debug() << std::endl;
			ERR_NG << "Skipping this undo action..." << std::endl;
		}
	}

	// Build the redo stack.
	for (const config & child : cfg.child_range("redo")) {
		try {
			undo_action_base * action = create_action(child);
			if ( undo_action* undoable_action = dynamic_cast<undo_action*>(action)) {
				redos_.push_back(undoable_action);
			} else {
				delete action;
				ERR_NG << "Error: redo contained action that is not undoable" << std::endl;
				ERR_NG << "config was: " << child.debug() << std::endl;
				ERR_NG << "Skipping this redo action..." << std::endl;
			}
		} catch (bad_lexical_cast &) {
			ERR_NG << "Error when parsing redo list from config: bad lexical cast." << std::endl;
			ERR_NG << "config was: " << child.debug() << std::endl;
			ERR_NG << "Skipping this redo action..." << std::endl;
		} catch (config::error& e) {
			ERR_NG << "Error when parsing redo list from config: " << e.what() << std::endl;
			ERR_NG << "config was: " << child.debug() << std::endl;
			ERR_NG << "Skipping this redo action..." << std::endl;
		}
	}
}
editor_controller::editor_controller(const config &game_config, CVideo& video, hero_map& heros, int mode)
	: controller_base(SDL_GetTicks(), game_config, video)
	, heros_(heros)
	, mode_(mode)
	, mouse_handler_base()
	, rng_(NULL)
	, rng_setter_(NULL)
	, map_contexts_()
	, current_context_index_(0)
	, gui_(NULL)
	, map_generators_()
	, tods_()
	, palette_()
	, floating_label_manager_(NULL)
	, do_quit_(false)
	, quit_mode_(EXIT_ERROR)
	, brushes_()
	, brush_(NULL)
	, mouse_actions_()
	, mouse_action_hints_()
	, mouse_action_(NULL)
	, toolbar_dirty_(true)
	, foreground_terrain_(t_translation::MOUNTAIN)
	, background_terrain_(t_translation::GRASS_LAND)
	, clipboard_()
	, auto_update_transitions_(preferences::editor::auto_update_transitions())
	, use_mdi_(preferences::editor::use_mdi())
	, default_dir_(preferences::editor::default_dir())
{
	create_default_context();

	if (default_dir_.empty()) {
		default_dir_ = get_dir(get_dir(get_user_data_dir() + "/editor") + "/maps");
	}
	init_gui(video);
	init_brushes(game_config);
	init_mouse_actions(game_config);
	init_map_generators(game_config);
	init_tods(game_config);
	init_sidebar(game_config);
	init_music(game_config);
	hotkey_set_mouse_action(gui2::teditor_theme::HOTKEY_EDITOR_TOOL_PAINT);
	rng_.reset(new rand_rng::rng());
	rng_setter_.reset(new rand_rng::set_random_generator(rng_.get()));
	get_map_context().set_starting_position_labels(gui());
	cursor::set(cursor::NORMAL);
	image::set_color_adjustment(preferences::editor::tod_r(), preferences::editor::tod_g(), preferences::editor::tod_b());
	refresh_all();
	events::raise_draw_event();

	map_type = tmap_type();
	if (mode_ != NONE) {
		BOOST_FOREACH (const config& type, game_config.child_range("map_type")) {
			const std::string& id = type["id"];
			if (mode == SIEGE && id == "siege") {
				map_type = tmap_type(*gui_, type);
			}
		}
	}
Beispiel #13
0
void manager::read_scenario(const config& scenario_cfg)
{
	BOOST_FOREACH(const config &ev, scenario_cfg.child_range("event")) {
		add_event_handler(ev);
	}
	BOOST_FOREACH(const std::string &id, utils::split(scenario_cfg["unit_wml_ids"])) {
		unit_wml_ids_.insert(id);
	}
Beispiel #14
0
void room_info::process_room_members(const config& data)
{
	members_.clear();
	for(const auto & m : data.child_range("member"))
	{
		members_.insert(m["name"]);
	}
}
Beispiel #15
0
void config::append_children(const config &cfg, const std::string& key)
{
	check_valid(cfg);

	for (const config &value : cfg.child_range(key)) {
		add_child(key, value);
	}
}
Beispiel #16
0
void config::append_children(const config &cfg, const std::string& key)
{
	check_valid(cfg);

	BOOST_FOREACH(const config &value, cfg.child_range(key)) {
		add_child(key, value);
	}
}
Beispiel #17
0
void add_color_info(const config &v)
{
	BOOST_FOREACH (const config &teamC, v.child_range("color_range"))
	{
		const config::attribute_value *a1 = teamC.get("id"),
			*a2 = teamC.get("rgb");
		if (!a1 || !a2) continue;
		std::string id = *a1;
		std::vector<Uint32> temp = string2rgb(*a2);
		team_rgb_range.insert(std::make_pair(id,color_range(temp)));
		team_rgb_name.push_back(std::make_pair(id, teamC["name"].t_str()));
		//generate palette of same name;
		std::vector<Uint32> tp = palette(team_rgb_range[id]);
		if (tp.empty()) continue;
		team_rgb_colors.insert(std::make_pair(id,tp));
		//if this is being used, output log of palette for artists use.
		std::ostringstream str;
		str << id << " = ";
		for (std::vector<Uint32>::const_iterator r = tp.begin(),
			    r_end = tp.end(), r_beg = r; r != r_end; ++r)
		{
			int red = ((*r) & 0x00FF0000) >> 16;
			int green = ((*r) & 0x0000FF00) >> 8;
			int blue = ((*r) & 0x000000FF);
			if (r != r_beg) str << ',';
			str << red << ',' << green << ',' << blue;
		}
	}

	std::map<std::string, color_range >& team_rgb_range_p = team_rgb_range;
	std::vector<std::pair<std::string, t_string > >& team_rgb_name_p = team_rgb_name;
	std::map<std::string, std::vector<Uint32> >& team_rgb_colors_p = team_rgb_colors;

	BOOST_FOREACH (const config &cp, v.child_range("color_palette"))
	{
		BOOST_FOREACH (const config::attribute &rgb, cp.attribute_range())
		{
			try {
				team_rgb_colors.insert(std::make_pair(rgb.first, string2rgb(rgb.second)));
			} catch (bad_lexical_cast&) {
				// throw config::error(_("Invalid team color: ") + rgb_it->second);
				// ERR_NG << "Invalid team color: " << rgb.second << "\n";
			}
		}
	}
}
Beispiel #18
0
void room_info::process_room_members(const config& data)
{
	members_.clear();
	FOREACH(const AUTO & m, data.child_range("member"))
	{
		members_.insert(m["name"]);
	}
}
Beispiel #19
0
/**
 * Returns a config with all partial resolutions of a theme expanded.
 *
 * @param theme                   The original object, whose objects need to be
 *                                expanded.
 *
 * @returns                       A new object with the expanded resolutions in
 *                                a theme. This object no longer contains
 *                                partial resolutions.
 */
static config expand_partialresolution(const config& theme)
{
	config result;

	// Add all the resolutions
	for(const auto& resolution : theme.child_range("resolution")) {
		result.add_child("resolution", resolution);
	}

	// Resolve all the partialresolutions
	for(const auto& part : theme.child_range("partialresolution")) {
		config resolution = get_resolution(result, part["inherits"]);
		resolution.merge_attributes(part);

		for(const auto& remove : part.child_range("remove")) {
			VALIDATE(!remove["id"].empty()
					, missing_mandatory_wml_key(
						  "[theme][partialresolution][remove]"
						, "id"));

			find_ref(remove["id"], resolution, true);
		}

		for(const auto& change : part.child_range("change")) {
			VALIDATE(!change["id"].empty()
					, missing_mandatory_wml_key(
						  "[theme][partialresolution][change]"
						, "id"));

			config& target = find_ref(change["id"], resolution, false);
			target.merge_attributes(change);
		}

		// cannot add [status] sub-elements, but who cares
		for(const auto& add : part.child_range("add")) {
			for(const auto& child : add.all_children_range()) {
				resolution.add_child(child.key, child.cfg);
			}
		}

		result.add_child("resolution", resolution);
	}

	return result;
}
static void unarchive_dir(const std::string& path, const config& cfg)
{
	std::string dir;
	if (cfg["name"].empty())
		dir = path;
	else
		dir = path + '/' + cfg["name"].str();

	make_directory(dir);

	BOOST_FOREACH(const config &d, cfg.child_range("dir")) {
		unarchive_dir(dir, d);
	}

	BOOST_FOREACH(const config &f, cfg.child_range("file")) {
		unarchive_file(dir, f);
	}
}
Beispiel #21
0
void read_stats(const config& cfg)
{
	fresh_stats();
	mid_scenario = cfg["mid_scenario"].to_bool();

	BOOST_FOREACH(const config &s, cfg.child_range("scenario")) {
		master_stats.push_back(scenario_stats(s));
	}
}
Beispiel #22
0
static void unarchive_dir(const std::string& path, const config& cfg)
{
	std::string dir;
	if (cfg["name"].empty())
		dir = path;
	else
		dir = path + '/' + cfg["name"].str();

	filesystem::make_directory(dir);

	for(const config &d : cfg.child_range("dir")) {
		unarchive_dir(dir, d);
	}

	for(const config &f : cfg.child_range("file")) {
		unarchive_file(dir, f);
	}
}
Beispiel #23
0
void theme::modify(const config &cfg)
{
	std::map<std::string,std::string> title_stash;
	std::vector<theme::menu>::iterator m;
	for (m = menus_.begin(); m != menus_.end(); ++m) {
		if (!m->title().empty() && !m->get_id().empty())
			title_stash[m->get_id()] = m->title();
	}

	std::vector<theme::action>::iterator a;
	for (a = actions_.begin(); a != actions_.end(); ++a) {
		if (!a->title().empty() && !a->get_id().empty())
			title_stash[a->get_id()] = a->title();
	}

	// Change existing theme objects.
	for(const config &c : cfg.child_range("change"))
	{
		std::string id = c["id"];
		std::string ref_id = c["ref"];
		theme::object &element = find_element(id);
		if (element.get_id() == id)
			set_object_location(element, c["rect"], ref_id);
	}

	// Add new theme objects.
	for(const config &c : cfg.child_range("add")) {
		add_object(c);
	}

	// Remove existent theme objects.
	for(const config &c : cfg.child_range("remove")) {
		remove_object(c["id"]);
	}

	for (m = menus_.begin(); m != menus_.end(); ++m) {
		if (title_stash.find(m->get_id()) != title_stash.end())
			m->set_title(title_stash[m->get_id()]);
	}
	for (a = actions_.begin(); a != actions_.end(); ++a) {
		if (title_stash.find(a->get_id()) != title_stash.end())
			a->set_title(title_stash[a->get_id()]);
	}
}
Beispiel #24
0
void load_hotkeys(const config& cfg)
{
	BOOST_FOREACH (const config &hk, cfg.child_range(hotkey_tag_name))
	{
		hotkey_item& h = get_hotkey(hk["command"].str());
		if(h.get_id() != HOTKEY_NULL) {
			h.load_from_config(hk);
		}
	}
}
Beispiel #25
0
builder_menu_button::builder_menu_button(const config& cfg)
	: builder_styled_widget(cfg)
	, retval_id_(cfg["return_value_id"])
	, retval_(cfg["return_value"])
	, options_()
{
	for(const auto& option : cfg.child_range("option")) {
		options_.push_back(option);
	}
}
Beispiel #26
0
void load_hotkeys(const config& cfg)
{
	foreach (const config &hk, cfg.child_range(hotkey_tag_name))
	{
		hotkey_item& h = get_hotkey(hk["command"]);
		if(h.get_id() != HOTKEY_NULL) {
			h.load_from_config(hk);
		}
	}
}
Beispiel #27
0
/**
 * Returns a copy of the wanted resolution.
 *
 * The function returns a copy since our caller uses a copy of this resolution
 * as base to expand a partial resolution.
 *
 * @param resolutions             A config object containing the expanded
 *                                resolutions.
 * @param id                      The id of the resolution to return.
 *
 * @throw config::error           If the @p id is not found.
 *
 * @returns                       A copy of the resolution config.
 */
static config get_resolution(const config& resolutions, const std::string& id)
{
	for(const auto& resolution : resolutions.child_range("resolution")) {
		if(resolution["id"] == id) {
			return resolution;
		}
	}

	throw config::error("[partialresolution] refers to non-existent [resolution] " + id);
}
cutter::surface_map cutter::cut_surface(surface surf, const config& conf)
{
	surface_map res;

	BOOST_FOREACH(const config &part, conf.child_range("part")) {
		add_sub_image(surf, res, &part);
	}

	return res;
}
Beispiel #29
0
/** Go to the next tips-of-the-day */
static void next_tip_of_day(config& tips_of_day, bool reverse = false)
{
	// we just rotate the tip list, to avoid the need to keep track
	// of the current one, and keep it valid, cycle it, etc...
	config::child_itors tips = tips_of_day.child_range("tip");
	if (tips.first != tips.second) {
		config::child_iterator direction = reverse ? tips.first+1 : tips.second-1;
		std::rotate(tips.first, direction, tips.second);
	}
}
Beispiel #30
0
// config就三个成员变量, values, children, orderer_children. orderer_child_ren可由children推出
// config被组织成一个树状结构
void wml_config_to_file(const std::string &fname, config &cfg, uint32_t nfiles, uint32_t sum_size, uint32_t modified)
{
	posix_file_t						fp = INVALID_FILE;
	uint32_t							max_str_len, bytertd, u32n; 

	std::vector<std::string>			tdomain;
	
	posix_print("<xwml.cpp>::wml_config_to_file------fname: %s\n", fname.c_str());

	posix_fopen(fname.c_str(), GENERIC_WRITE, CREATE_ALWAYS, fp);
	if (fp == INVALID_FILE) {
		posix_print("------<xwml.cpp>::wml_config_to_file, cannot create %s for wrtie\n", fname.c_str());
		goto exit;
	}
	// 

	max_str_len = posix_max(WMLBIN_MARK_CONFIG_LEN, WMLBIN_MARK_VALUE_LEN);
	posix_fseek(fp, 16 + sizeof(max_str_len) + sizeof(u32n), 0);

	// write [textdomain]
	BOOST_FOREACH (const config &d, cfg.child_range("textdomain")) {
		if (std::find(tdomain.begin(), tdomain.end(), d.get("name")->str()) != tdomain.end()) {
			continue;
		}
		tdomain.push_back(d.get("name")->str());
		u32n = tdomain.back().size();
		posix_fwrite(fp, &u32n, sizeof(u32n), bytertd);
		posix_fwrite(fp, tdomain.back().c_str(), u32n, bytertd);
	}

	wml_config_to_fp(fp, cfg, &max_str_len, tdomain, 0);

	// update max_str_len/textdomain_count
	posix_fseek(fp, 0, 0);

	// 0--15
	u32n = mmioFOURCC('X', 'W', 'M', 'L');
	posix_fwrite(fp, &u32n, 4, bytertd);
	posix_fwrite(fp, &nfiles, 4, bytertd);
	posix_fwrite(fp, &sum_size, 4, bytertd);
	posix_fwrite(fp, &modified, 4, bytertd);
	// 16--19(max_str_len)
	posix_fwrite(fp, &max_str_len, sizeof(max_str_len), bytertd);
	// 20--23(textdomain_count)
	u32n = tdomain.size();
	posix_fwrite(fp, &u32n, sizeof(u32n), bytertd);

	posix_print("------<xwml.cpp>::wml_config_to_file, return\n");
exit:
	if (fp != INVALID_FILE) {
		posix_fclose(fp);
	}

	return;
}