推
This commit is contained in:
306
source/Asset/Asset_Audio.hpp
Normal file
306
source/Asset/Asset_Audio.hpp
Normal file
@@ -0,0 +1,306 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include "rapidxml/rapidxml.hpp"
|
||||
|
||||
class AudioConfigReader
|
||||
{
|
||||
public:
|
||||
// --------------------------
|
||||
// 1. 结构体定义:放在类内public区,外部可通过 AudioConfigReader::SoundEffect 访问
|
||||
// --------------------------
|
||||
struct SoundEffect
|
||||
{
|
||||
std::string file_path; // 文件路径(FILE属性)
|
||||
int volume_adjust = 100; // 音量调整(默认100)
|
||||
int priority = 0; // 优先级(默认0)
|
||||
};
|
||||
|
||||
struct RandomItem
|
||||
{
|
||||
std::string tag; // 关联的音效ID(TAG属性)
|
||||
int prob = 0; // 概率(PROB属性)
|
||||
};
|
||||
|
||||
struct RandomSoundGroup
|
||||
{
|
||||
std::vector<RandomItem> items; // 组内所有项
|
||||
int delay = 0; // 延迟(DELAY属性)
|
||||
int loop_delay = 0; // 循环延迟
|
||||
int loop_delay_range = 0; // 循环延迟范围
|
||||
};
|
||||
|
||||
struct Music
|
||||
{
|
||||
std::string file_path; // 文件路径(FILE属性)
|
||||
int loop_delay = 0; // 循环延迟(LOOP_DELAY属性)
|
||||
};
|
||||
|
||||
public:
|
||||
// 构造函数:初始化解析器
|
||||
AudioConfigReader() = default;
|
||||
|
||||
// 析构函数:清理资源
|
||||
~AudioConfigReader() = default;
|
||||
|
||||
// 核心函数:解析XML文件(返回是否成功)
|
||||
bool LoadFromFile(const std::string &xml_path)
|
||||
{
|
||||
// 1. 读取XML文件内容
|
||||
std::ifstream file(xml_path, std::ios::binary);
|
||||
if (!file.is_open())
|
||||
{
|
||||
throw std::runtime_error("无法打开XML文件: " + xml_path);
|
||||
}
|
||||
std::string xml_content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
// 2. 解析XML
|
||||
rapidxml::xml_document<> doc;
|
||||
try
|
||||
{
|
||||
doc.parse<rapidxml::parse_default>(&xml_content[0]);
|
||||
}
|
||||
catch (const rapidxml::parse_error &e)
|
||||
{
|
||||
throw std::runtime_error("XML解析错误: " + std::string(e.what()) +
|
||||
"(位置: " + std::string(e.where<char>()) + ")");
|
||||
}
|
||||
|
||||
// 3. 获取根节点
|
||||
rapidxml::xml_node<> *root = doc.first_node("AudioTagDatabase");
|
||||
if (!root)
|
||||
{
|
||||
throw std::runtime_error("XML根节点错误: 找不到AudioTagDatabase");
|
||||
}
|
||||
|
||||
// 4. 解析所有节点
|
||||
ParseEffects(root); // 解析<EFFECT>
|
||||
ParseRandomGroups(root); // 解析<RANDOM>
|
||||
ParseMusics(root); // 解析<MUSIC>
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// 接口1:获取音效配置(<EFFECT>)
|
||||
// ------------------------------
|
||||
bool HasEffect(const std::string &effect_id) const
|
||||
{
|
||||
return m_effects.find(effect_id) != m_effects.end();
|
||||
}
|
||||
|
||||
const SoundEffect &GetEffect(const std::string &effect_id) const
|
||||
{
|
||||
auto it = m_effects.find(effect_id);
|
||||
if (it == m_effects.end())
|
||||
{
|
||||
throw std::out_of_range("音效ID不存在: " + effect_id);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 获取所有音效ID列表
|
||||
std::vector<std::string> GetAllEffectIds() const
|
||||
{
|
||||
return GetAllKeys(m_effects);
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// 接口2:获取随机音效组配置(<RANDOM>)
|
||||
// ------------------------------
|
||||
bool HasRandomGroup(const std::string &group_id) const
|
||||
{
|
||||
return m_random_groups.find(group_id) != m_random_groups.end();
|
||||
}
|
||||
|
||||
const RandomSoundGroup &GetRandomGroup(const std::string &group_id) const
|
||||
{
|
||||
auto it = m_random_groups.find(group_id);
|
||||
if (it == m_random_groups.end())
|
||||
{
|
||||
throw std::out_of_range("随机组ID不存在: " + group_id);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 获取所有随机组ID列表
|
||||
std::vector<std::string> GetAllRandomGroupIds() const
|
||||
{
|
||||
return GetAllKeys(m_random_groups);
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// 接口3:获取背景音乐配置(<MUSIC>)
|
||||
// ------------------------------
|
||||
bool HasMusic(const std::string &music_id) const
|
||||
{
|
||||
return m_musics.find(music_id) != m_musics.end();
|
||||
}
|
||||
|
||||
const Music &GetMusic(const std::string &music_id) const
|
||||
{
|
||||
auto it = m_musics.find(music_id);
|
||||
if (it == m_musics.end())
|
||||
{
|
||||
throw std::out_of_range("背景音乐ID不存在: " + music_id);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 获取所有背景音乐ID列表
|
||||
std::vector<std::string> GetAllMusicIds() const
|
||||
{
|
||||
return GetAllKeys(m_musics);
|
||||
}
|
||||
|
||||
private:
|
||||
// 辅助函数:解析<EFFECT>节点
|
||||
void ParseEffects(rapidxml::xml_node<> *root)
|
||||
{
|
||||
for (rapidxml::xml_node<> *node = root->first_node("EFFECT");
|
||||
node; node = node->next_sibling("EFFECT"))
|
||||
{
|
||||
|
||||
// 必选属性:ID和FILE
|
||||
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
|
||||
rapidxml::xml_attribute<> *file_attr = node->first_attribute("FILE");
|
||||
if (!id_attr || !file_attr)
|
||||
{
|
||||
continue; // 跳过无效节点
|
||||
}
|
||||
|
||||
SoundEffect effect;
|
||||
effect.file_path = NormalizePath(file_attr->value()); // 统一路径分隔符
|
||||
|
||||
// 可选属性:VOLUME_ADJUST
|
||||
if (auto attr = node->first_attribute("VOLUME_ADJUST"))
|
||||
{
|
||||
effect.volume_adjust = std::stoi(attr->value());
|
||||
}
|
||||
|
||||
// 可选属性:PRIORITY
|
||||
if (auto attr = node->first_attribute("PRIORITY"))
|
||||
{
|
||||
effect.priority = std::stoi(attr->value());
|
||||
}
|
||||
|
||||
m_effects[id_attr->value()] = effect;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:解析<RANDOM>节点
|
||||
void ParseRandomGroups(rapidxml::xml_node<> *root)
|
||||
{
|
||||
for (rapidxml::xml_node<> *node = root->first_node("RANDOM");
|
||||
node; node = node->next_sibling("RANDOM"))
|
||||
{
|
||||
|
||||
// 必选属性:ID
|
||||
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
|
||||
if (!id_attr)
|
||||
{
|
||||
continue; // 跳过无效节点
|
||||
}
|
||||
|
||||
RandomSoundGroup group;
|
||||
|
||||
// 可选属性:延迟相关
|
||||
if (auto attr = node->first_attribute("DELAY"))
|
||||
{
|
||||
group.delay = std::stoi(attr->value());
|
||||
}
|
||||
if (auto attr = node->first_attribute("LOOP_DELAY"))
|
||||
{
|
||||
group.loop_delay = std::stoi(attr->value());
|
||||
}
|
||||
if (auto attr = node->first_attribute("LOOP_DELAY_RANGE"))
|
||||
{
|
||||
group.loop_delay_range = std::stoi(attr->value());
|
||||
}
|
||||
|
||||
// 解析子节点<ITEM>
|
||||
for (rapidxml::xml_node<> *item_node = node->first_node("ITEM");
|
||||
item_node; item_node = item_node->next_sibling("ITEM"))
|
||||
{
|
||||
|
||||
rapidxml::xml_attribute<> *tag_attr = item_node->first_attribute("TAG");
|
||||
rapidxml::xml_attribute<> *prob_attr = item_node->first_attribute("PROB");
|
||||
if (!tag_attr || !prob_attr)
|
||||
{
|
||||
continue; // 跳过无效项
|
||||
}
|
||||
|
||||
group.items.push_back({tag_attr->value(),
|
||||
std::stoi(prob_attr->value())});
|
||||
}
|
||||
|
||||
m_random_groups[id_attr->value()] = group;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:解析<MUSIC>节点
|
||||
void ParseMusics(rapidxml::xml_node<> *root)
|
||||
{
|
||||
for (rapidxml::xml_node<> *node = root->first_node("MUSIC");
|
||||
node; node = node->next_sibling("MUSIC"))
|
||||
{
|
||||
|
||||
// 必选属性:ID和FILE
|
||||
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
|
||||
rapidxml::xml_attribute<> *file_attr = node->first_attribute("FILE");
|
||||
if (!id_attr || !file_attr)
|
||||
{
|
||||
continue; // 跳过无效节点
|
||||
}
|
||||
|
||||
Music music;
|
||||
music.file_path = NormalizePath(file_attr->value()); // 统一路径分隔符
|
||||
|
||||
// 可选属性:LOOP_DELAY
|
||||
if (auto attr = node->first_attribute("LOOP_DELAY"))
|
||||
{
|
||||
music.loop_delay = std::stoi(attr->value());
|
||||
}
|
||||
|
||||
m_musics[id_attr->value()] = music;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:统一路径分隔符(将\转为/,兼容跨平台)
|
||||
std::string NormalizePath(const std::string &path)
|
||||
{
|
||||
std::string normalized = path;
|
||||
for (char &c : normalized)
|
||||
{
|
||||
if (c == '\\')
|
||||
{
|
||||
c = '/';
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// 辅助函数:获取哈希表中所有key
|
||||
template <typename Map>
|
||||
std::vector<std::string> GetAllKeys(const Map &map) const
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
keys.reserve(map.size());
|
||||
for (const auto &pair : map)
|
||||
{
|
||||
keys.push_back(pair.first);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
private:
|
||||
// 存储解析后的数据
|
||||
std::unordered_map<std::string, SoundEffect> m_effects; // 音效映射(ID -> 音效)
|
||||
std::unordered_map<std::string, RandomSoundGroup> m_random_groups; // 随机组映射(ID -> 随机组)
|
||||
std::unordered_map<std::string, Music> m_musics; // 背景音乐映射(ID -> 音乐)
|
||||
};
|
||||
233
source/Asset/Asset_SoundPack.cpp
Normal file
233
source/Asset/Asset_SoundPack.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
#include "Asset_SoundPack.h"
|
||||
Asset_SoundPack::Asset_SoundPack()
|
||||
{
|
||||
int device = -1; // 使用默认设备
|
||||
unsigned long freq = 44100; // 采样频率,PCM常用的采样率之一,可以按需调整
|
||||
|
||||
// 构造NPK信息
|
||||
InitNpkList();
|
||||
// 解析audio.xml
|
||||
XmlConfig.LoadFromFile("audio.xml");
|
||||
|
||||
// 初始化SDL_mixer,支持OGG格式
|
||||
// 44100: 采样率, MIX_DEFAULT_FORMAT: 音频格式, 2: 声道数(立体声), 4096: 缓冲区大小
|
||||
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 8192) < 0)
|
||||
{
|
||||
SDL_LogError(0, "SDL_mixer初始化失败! Mix_Error: %s\n", Mix_GetError());
|
||||
}
|
||||
if (Mix_Init(MIX_INIT_MP3 | MIX_INIT_OGG) < 0)
|
||||
{
|
||||
SDL_LogError(0, "Mix_Init failed: %s\n", Mix_GetError());
|
||||
}
|
||||
// 分配通道
|
||||
ChannelCount = Mix_AllocateChannels(64);
|
||||
SetAllChannelVolume(0);
|
||||
}
|
||||
|
||||
Asset_SoundPack::~Asset_SoundPack()
|
||||
{
|
||||
}
|
||||
|
||||
void Asset_SoundPack::InitNpkList()
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
std::string path = "SoundPacks/";
|
||||
dir = opendir(path.c_str());
|
||||
|
||||
while ((ent = readdir(dir)))
|
||||
{
|
||||
// 跳过.和..目录
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
std::string RealPath = path + ent->d_name;
|
||||
Ifstream_NPK Fs;
|
||||
Fs.open(RealPath.c_str(), std::ios::in | std::ios::binary);
|
||||
if (Fs.is_open())
|
||||
{
|
||||
std::string Header = Fs.ReadString();
|
||||
// 如果是NPK
|
||||
if (Header == "NeoplePack_Bill")
|
||||
{
|
||||
// 读取img数量
|
||||
int ImageCount = Fs.ReadInt();
|
||||
|
||||
for (int i = 0; i < ImageCount; ++i)
|
||||
{
|
||||
// 直接读取当前项的偏移、长度和路径
|
||||
auto offset = Fs.ReadUnsignedInt();
|
||||
auto length = Fs.ReadUnsignedInt();
|
||||
auto path = Fs.ReadInfo();
|
||||
|
||||
// 构造 WAV 并插入映射表
|
||||
lp_arr[path] = WAV{
|
||||
offset, // offset
|
||||
length, // size
|
||||
path, // lpWavName(直接复用读取的path)
|
||||
RealPath, // lpBelongsFile
|
||||
i // img_index
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
void Asset_SoundPack::Reclaims()
|
||||
{
|
||||
}
|
||||
|
||||
Mix_Chunk *Asset_SoundPack::GetOgg(const std::string &lpWavName)
|
||||
{
|
||||
|
||||
if (map_sound.find(lpWavName) != map_sound.end())
|
||||
{
|
||||
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
|
||||
return map_sound[lpWavName].lpMusic;
|
||||
}
|
||||
// 在NPK映射表中找到
|
||||
if (lp_arr.find(lpWavName) != lp_arr.end())
|
||||
{
|
||||
WAV &wav = lp_arr[lpWavName];
|
||||
if (wav.lpBelongsFile.empty())
|
||||
return nullptr;
|
||||
Ifstream_NPK Fs;
|
||||
Fs.open(wav.lpBelongsFile.c_str(), std::ios::in | std::ios::binary);
|
||||
if (Fs.is_open())
|
||||
{
|
||||
Fs.seekg(wav.offset, std::ios::beg);
|
||||
auto buffer = Fs.ReadCustomSize(wav.size);
|
||||
SDL_RWops *rw = SDL_RWFromConstMem(buffer, wav.size);
|
||||
if (!rw)
|
||||
{
|
||||
SDL_Log("创建内存流失败: %s\n", SDL_GetError());
|
||||
Mix_CloseAudio();
|
||||
SDL_Quit();
|
||||
return nullptr;
|
||||
}
|
||||
Mix_Chunk *music = Mix_LoadWAV_RW(rw, 0);
|
||||
if (!music)
|
||||
{
|
||||
SDL_Log("加载OGG失败: %s\n", Mix_GetError());
|
||||
SDL_RWclose(rw); // 手动关闭流
|
||||
Mix_CloseAudio();
|
||||
SDL_Quit();
|
||||
return nullptr;
|
||||
}
|
||||
map_sound[lpWavName].lpMusic = music;
|
||||
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
|
||||
return music;
|
||||
}
|
||||
}
|
||||
// 去Music文件夹中寻找
|
||||
else
|
||||
{
|
||||
Mix_Chunk *music = Mix_LoadWAV(lpWavName.c_str());
|
||||
if (!music)
|
||||
{
|
||||
SDL_Log("加载OGG失败: %s\n", Mix_GetError());
|
||||
Mix_CloseAudio();
|
||||
SDL_Quit();
|
||||
return nullptr;
|
||||
}
|
||||
map_sound[lpWavName].lpMusic = music;
|
||||
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
|
||||
return music;
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_SoundPack::PlayAudio(const std::string Key)
|
||||
{
|
||||
std::string RealKey = Key;
|
||||
// 先判断是不是随机组 如果是随机组去里面调出真正要播放的Key
|
||||
if (XmlConfig.HasRandomGroup(Key))
|
||||
{
|
||||
auto Group = XmlConfig.GetRandomGroup(Key);
|
||||
int RandNum = rand() % 100;
|
||||
for (auto &item : Group.items)
|
||||
{
|
||||
if (RandNum <= item.prob)
|
||||
{
|
||||
RealKey = item.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是特效音频
|
||||
if (XmlConfig.HasEffect(Key))
|
||||
{
|
||||
std::string oggPath = XmlConfig.GetEffect(Key).file_path;
|
||||
int volume = XmlConfig.GetEffect(Key).volume_adjust;
|
||||
PlayEffect(oggPath, volume);
|
||||
}
|
||||
// 如果是背景音乐
|
||||
else if (XmlConfig.HasMusic(Key))
|
||||
{
|
||||
std::string oggPath = XmlConfig.GetMusic(Key).file_path;
|
||||
PlayMusic(Key, oggPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_LogError(0, "找不到音频: %s\n", Key.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_SoundPack::StopAudio(const std::string Key)
|
||||
{
|
||||
StopChannel(backgroud_music_map[Key]);
|
||||
backgroud_music_map.erase(Key);
|
||||
}
|
||||
|
||||
void Asset_SoundPack::PlayMusic(const std::string Key, const std::string oggpath)
|
||||
{
|
||||
auto ogg = GetOgg(oggpath);
|
||||
if (ogg)
|
||||
{
|
||||
int channel = FindFreeChannelInRange(0, 4);
|
||||
backgroud_music_map[Key] = Mix_PlayChannel(channel, ogg, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_SoundPack::PlayEffect(const std::string Key, int Volume)
|
||||
{
|
||||
auto ogg = GetOgg(Key);
|
||||
if (ogg)
|
||||
{
|
||||
int channel = FindFreeChannelInRange(4, ChannelCount - 1);
|
||||
Mix_VolumeChunk(ogg, Volume);
|
||||
Mix_PlayChannel(channel, ogg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_SoundPack::StopChannel(int Channel)
|
||||
{
|
||||
Mix_HaltChannel(Channel); // 停止指定通道的音效
|
||||
}
|
||||
|
||||
void Asset_SoundPack::SetAllChannelVolume(int Volume)
|
||||
{
|
||||
Mix_Volume(-1, Volume);
|
||||
}
|
||||
|
||||
std::map<std::string, int> Asset_SoundPack::GetBackgroudMusicVector()
|
||||
{
|
||||
return backgroud_music_map;
|
||||
}
|
||||
|
||||
int Asset_SoundPack::FindFreeChannelInRange(int startChannel, int endChannel)
|
||||
{
|
||||
// 遍历通道(若总通道数小于32,则只检查到最后一个通道)
|
||||
for (int channel = startChannel; channel <= endChannel; channel++)
|
||||
{
|
||||
// 检查通道是否空闲(Mix_Playing返回0表示空闲)
|
||||
if (Mix_Playing(channel) == 0)
|
||||
{
|
||||
return channel; // 返回第一个空闲通道
|
||||
}
|
||||
}
|
||||
|
||||
// 若所有通道都在使用中
|
||||
return -1;
|
||||
}
|
||||
88
source/Asset/Asset_SoundPack.h
Normal file
88
source/Asset/Asset_SoundPack.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <dirent.h>
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
#include <SDL_mixer.h>
|
||||
#include "Tool/Ifstream_NPK.h"
|
||||
#include "Asset/Asset_Audio.hpp"
|
||||
|
||||
class Asset_SoundPack
|
||||
{
|
||||
public:
|
||||
struct WAV
|
||||
{
|
||||
unsigned int offset; // 偏移
|
||||
unsigned int size; // 大小
|
||||
std::string lpWavName; // img文件的路径
|
||||
std::string lpBelongsFile; // 这个img属于哪个npk文件
|
||||
int img_index; // img文件在npk文件里的序号
|
||||
};
|
||||
|
||||
struct NpkInfo
|
||||
{
|
||||
int Offset;
|
||||
int Length;
|
||||
std::string Path;
|
||||
};
|
||||
|
||||
struct MusicInfo
|
||||
{
|
||||
/**上次使用时间 */
|
||||
Uint64 LastUseTime;
|
||||
/**音频指针 */
|
||||
Mix_Chunk *lpMusic;
|
||||
};
|
||||
|
||||
public:
|
||||
Asset_SoundPack(const Asset_SoundPack &) = delete;
|
||||
Asset_SoundPack &operator=(const Asset_SoundPack &) = delete;
|
||||
Asset_SoundPack(Asset_SoundPack &&) = delete;
|
||||
Asset_SoundPack &operator=(Asset_SoundPack &&) = delete;
|
||||
// 全局访问点
|
||||
static Asset_SoundPack &GetInstance()
|
||||
{
|
||||
static Asset_SoundPack instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**音频NPK信息表 */
|
||||
std::map<std::string, WAV> lp_arr;
|
||||
/**音频储存表 */
|
||||
std::map<std::string, MusicInfo> map_sound;
|
||||
/**audio信息表 */
|
||||
AudioConfigReader XmlConfig;
|
||||
/**正在播放的背景音乐表 */
|
||||
std::map<std::string, int> backgroud_music_map;
|
||||
/**总通道数 */
|
||||
int ChannelCount;
|
||||
|
||||
public:
|
||||
Asset_SoundPack(/* args */);
|
||||
~Asset_SoundPack();
|
||||
|
||||
void InitNpkList();
|
||||
|
||||
void Reclaims();
|
||||
|
||||
Mix_Chunk *GetOgg(const std::string &lpWavName);
|
||||
|
||||
/**播放音频 */
|
||||
void PlayAudio(const std::string Key);
|
||||
/**停止音频 */
|
||||
void StopAudio(const std::string Key);
|
||||
|
||||
void PlayMusic(const std::string Key, const std::string oggpath);
|
||||
void PlayEffect(const std::string Key, int Volume);
|
||||
|
||||
/**停止通道播放音频 */
|
||||
void StopChannel(int Channel);
|
||||
/**设置所有通道音量 */
|
||||
void SetAllChannelVolume(int Volume);
|
||||
/**获取正在播放的背景音乐 */
|
||||
std::map<std::string, int> GetBackgroudMusicVector();
|
||||
|
||||
/**获取空闲的通道 */
|
||||
int FindFreeChannelInRange(int Start, int End);
|
||||
};
|
||||
2596
source/Asset/rapidxml/rapidxml.hpp
Normal file
2596
source/Asset/rapidxml/rapidxml.hpp
Normal file
File diff suppressed because it is too large
Load Diff
174
source/Asset/rapidxml/rapidxml_iterators.hpp
Normal file
174
source/Asset/rapidxml/rapidxml_iterators.hpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#define RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_iterators.hpp This file contains rapidxml iterators
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Iterator of child nodes of xml_node
|
||||
template<class Ch>
|
||||
class node_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_node<Ch> value_type;
|
||||
typedef typename xml_node<Ch> &reference;
|
||||
typedef typename xml_node<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
node_iterator()
|
||||
: m_node(0)
|
||||
{
|
||||
}
|
||||
|
||||
node_iterator(xml_node<Ch> *node)
|
||||
: m_node(node->first_node())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_node);
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_node);
|
||||
return m_node;
|
||||
}
|
||||
|
||||
node_iterator& operator++()
|
||||
{
|
||||
assert(m_node);
|
||||
m_node = m_node->next_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator++(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
node_iterator& operator--()
|
||||
{
|
||||
assert(m_node && m_node->previous_sibling());
|
||||
m_node = m_node->previous_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator--(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node == rhs.m_node;
|
||||
}
|
||||
|
||||
bool operator !=(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node != rhs.m_node;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_node<Ch> *m_node;
|
||||
|
||||
};
|
||||
|
||||
//! Iterator of child attributes of xml_node
|
||||
template<class Ch>
|
||||
class attribute_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_attribute<Ch> value_type;
|
||||
typedef typename xml_attribute<Ch> &reference;
|
||||
typedef typename xml_attribute<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
attribute_iterator()
|
||||
: m_attribute(0)
|
||||
{
|
||||
}
|
||||
|
||||
attribute_iterator(xml_node<Ch> *node)
|
||||
: m_attribute(node->first_attribute())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return *m_attribute;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return m_attribute;
|
||||
}
|
||||
|
||||
attribute_iterator& operator++()
|
||||
{
|
||||
assert(m_attribute);
|
||||
m_attribute = m_attribute->next_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator++(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
attribute_iterator& operator--()
|
||||
{
|
||||
assert(m_attribute && m_attribute->previous_attribute());
|
||||
m_attribute = m_attribute->previous_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator--(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute == rhs.m_attribute;
|
||||
}
|
||||
|
||||
bool operator !=(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute != rhs.m_attribute;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_attribute<Ch> *m_attribute;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
421
source/Asset/rapidxml/rapidxml_print.hpp
Normal file
421
source/Asset/rapidxml/rapidxml_print.hpp
Normal file
@@ -0,0 +1,421 @@
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (*begin == noexpand)
|
||||
{
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*begin)
|
||||
{
|
||||
case Ch('<'):
|
||||
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('>'):
|
||||
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('\''):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('"'):
|
||||
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('&'):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||
break;
|
||||
default:
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
}
|
||||
++begin; // Step to next character
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fill given output iterator with repetitions of the same character
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find character
|
||||
template<class Ch, Ch ch>
|
||||
inline bool find_char(const Ch *begin, const Ch *end)
|
||||
{
|
||||
while (begin != end)
|
||||
if (*begin++ == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal printing operations
|
||||
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print proper node type
|
||||
switch (node->type())
|
||||
{
|
||||
|
||||
// Document
|
||||
case node_document:
|
||||
out = print_children(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Element
|
||||
case node_element:
|
||||
out = print_element_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Data
|
||||
case node_data:
|
||||
out = print_data_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// CDATA
|
||||
case node_cdata:
|
||||
out = print_cdata_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Declaration
|
||||
case node_declaration:
|
||||
out = print_declaration_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Comment
|
||||
case node_comment:
|
||||
out = print_comment_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Doctype
|
||||
case node_doctype:
|
||||
out = print_doctype_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Pi
|
||||
case node_pi:
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
|
||||
// Return modified iterator
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print children of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||
out = print_node(out, child, flags, indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
if (attribute->name() && attribute->value())
|
||||
{
|
||||
// Print attribute name
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||
*out = Ch('='), ++out;
|
||||
// Print attribute value using appropriate quote type
|
||||
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||
{
|
||||
*out = Ch('\''), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||
*out = Ch('\''), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = Ch('"'), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||
*out = Ch('"'), ++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_data);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_cdata);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'); ++out;
|
||||
*out = Ch('!'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
*out = Ch('C'); ++out;
|
||||
*out = Ch('D'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('T'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch('>'); ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print element node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_element);
|
||||
|
||||
// Print element name and attributes, if any
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// If node is childless
|
||||
if (node->value_size() == 0 && !node->first_node())
|
||||
{
|
||||
// Print childless node tag ending
|
||||
*out = Ch('/'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print normal node tag ending
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
// Test if node contains a single data node only (and no other nodes)
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
if (!child)
|
||||
{
|
||||
// If node has no children, only print its value without indenting
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
}
|
||||
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||
{
|
||||
// If node has a sole data child, only print its value without indenting
|
||||
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print all children with full indenting
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
out = print_children(out, node, flags, indent + 1);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
}
|
||||
|
||||
// Print node end
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('/'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print declaration node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print declaration start
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('x'), ++out;
|
||||
*out = Ch('m'), ++out;
|
||||
*out = Ch('l'), ++out;
|
||||
|
||||
// Print attributes
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// Print declaration end
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print comment node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_comment);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print doctype node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_doctype);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('D'), ++out;
|
||||
*out = Ch('O'), ++out;
|
||||
*out = Ch('C'), ++out;
|
||||
*out = Ch('T'), ++out;
|
||||
*out = Ch('Y'), ++out;
|
||||
*out = Ch('P'), ++out;
|
||||
*out = Ch('E'), ++out;
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print pi node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_pi);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Printing
|
||||
|
||||
//! Prints XML to given output iterator.
|
||||
//! \param out Output iterator to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||
{
|
||||
return print(out, node);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
122
source/Asset/rapidxml/rapidxml_utils.hpp
Normal file
122
source/Asset/rapidxml/rapidxml_utils.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#define RAPIDXML_UTILS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
|
||||
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Represents data loaded from a file
|
||||
template<class Ch = char>
|
||||
class file
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
|
||||
//! \param filename Filename to load.
|
||||
file(const char *filename)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Open stream
|
||||
basic_ifstream<Ch> stream(filename, ios::binary);
|
||||
if (!stream)
|
||||
throw runtime_error(string("cannot open file ") + filename);
|
||||
stream.unsetf(ios::skipws);
|
||||
|
||||
// Determine stream size
|
||||
stream.seekg(0, ios::end);
|
||||
size_t size = stream.tellg();
|
||||
stream.seekg(0);
|
||||
|
||||
// Load data and add terminating 0
|
||||
m_data.resize(size + 1);
|
||||
stream.read(&m_data.front(), static_cast<streamsize>(size));
|
||||
m_data[size] = 0;
|
||||
}
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor
|
||||
//! \param stream Stream to load from
|
||||
file(std::basic_istream<Ch> &stream)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Load data and add terminating 0
|
||||
stream.unsetf(ios::skipws);
|
||||
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
|
||||
if (stream.fail() || stream.bad())
|
||||
throw runtime_error("error reading stream");
|
||||
m_data.push_back(0);
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
Ch *data()
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
const Ch *data() const
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data size.
|
||||
//! \return Size of file data, in characters.
|
||||
std::size_t size() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Ch> m_data; // File data
|
||||
|
||||
};
|
||||
|
||||
//! Counts children of node. Time complexity is O(n).
|
||||
//! \return Number of children of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_children(xml_node<Ch> *node)
|
||||
{
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
std::size_t count = 0;
|
||||
while (child)
|
||||
{
|
||||
++count;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! Counts attributes of node. Time complexity is O(n).
|
||||
//! \return Number of attributes of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_attributes(xml_node<Ch> *node)
|
||||
{
|
||||
xml_attribute<Ch> *attr = node->first_attribute();
|
||||
std::size_t count = 0;
|
||||
while (attr)
|
||||
{
|
||||
++count;
|
||||
attr = attr->next_attribute();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user