Code cleanup and some new unittests for edgecases.

pull/4705/head
Kim Kulling 2022-08-27 14:07:45 +02:00
parent 46e571e497
commit 14186bcd6b
4 changed files with 604 additions and 518 deletions

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -48,19 +47,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <fstream> #include <fstream>
#include "MMDCpp14.h" #include "MMDCpp14.h"
namespace pmd namespace pmd {
{
class PmdHeader struct PmdHeader {
{
public:
std::string name; std::string name;
std::string name_english; std::string name_english;
std::string comment; std::string comment;
std::string comment_english; std::string comment_english;
bool Read(std::ifstream* stream) PmdHeader() = default;
{ ~PmdHeader() = default;
char buffer[256];
bool Read(std::ifstream *stream) {
if (stream == nullptr) {
return false;
}
char buffer[256] = {};
stream->read(buffer, 20); stream->read(buffer, 20);
name = std::string(buffer); name = std::string(buffer);
stream->read(buffer, 256); stream->read(buffer, 256);
@ -68,47 +70,50 @@ namespace pmd
return true; return true;
} }
bool ReadExtension(std::ifstream* stream) bool ReadExtension(std::ifstream *stream) {
{ if (stream == nullptr) {
char buffer[256]; return false;
}
char buffer[256] = {};
stream->read(buffer, 20); stream->read(buffer, 20);
name_english = std::string(buffer); name_english = std::string(buffer);
stream->read(buffer, 256); stream->read(buffer, 256);
comment_english = std::string(buffer); comment_english = std::string(buffer);
return true; return true;
} }
}; };
class PmdVertex struct PmdVertex {
{
public:
float position[3]; float position[3];
float normal[3]; float normal[3];
float uv[2]; float uv[2];
uint16_t bone_index[2]; uint16_t bone_index[2];
uint8_t bone_weight; uint8_t bone_weight;
bool edge_invisible; bool edge_invisible;
bool Read(std::ifstream* stream) PmdVertex() :
{ position{ 0.0f }, normal{ 0.0f }, uv{ 0.0f }, bone_index{ 0 }, bone_weight(0), edge_invisible(false) {}
stream->read((char*) position, sizeof(float) * 3);
stream->read((char*) normal, sizeof(float) * 3); ~PmdVertex() = default;
stream->read((char*) uv, sizeof(float) * 2);
stream->read((char*) bone_index, sizeof(uint16_t) * 2); bool Read(std::ifstream *stream) {
stream->read((char*) &bone_weight, sizeof(uint8_t)); if (stream == nullptr) {
stream->read((char*) &edge_invisible, sizeof(uint8_t)); return false;
}
stream->read((char *)position, sizeof(float) * 3);
stream->read((char *)normal, sizeof(float) * 3);
stream->read((char *)uv, sizeof(float) * 2);
stream->read((char *)bone_index, sizeof(uint16_t) * 2);
stream->read((char *)&bone_weight, sizeof(uint8_t));
stream->read((char *)&edge_invisible, sizeof(uint8_t));
return true; return true;
} }
}; };
class PmdMaterial struct PmdMaterial {
{
public:
float diffuse[4]; float diffuse[4];
float power; float power;
float specular[3]; float specular[3];
@ -119,34 +124,41 @@ namespace pmd
std::string texture_filename; std::string texture_filename;
std::string sphere_filename; std::string sphere_filename;
bool Read(std::ifstream* stream) PmdMaterial() :
{ diffuse{ 0.0f }, power(0.0f), specular{ 0.0f }, ambient{ 0.0f }, toon_index(0), edge_flag(0), index_count(0), texture_filename(), sphere_filename() {}
char buffer[20];
stream->read((char*) &diffuse, sizeof(float) * 4); ~PmdMaterial() = default;
stream->read((char*) &power, sizeof(float));
stream->read((char*) &specular, sizeof(float) * 3); bool Read(std::ifstream *stream) {
stream->read((char*) &ambient, sizeof(float) * 3); if (stream == nullptr) {
stream->read((char*) &toon_index, sizeof(uint8_t)); return false;
stream->read((char*) &edge_flag, sizeof(uint8_t)); }
stream->read((char*) &index_count, sizeof(uint32_t)); constexpr size_t BufferSize = 20;
stream->read((char*) &buffer, sizeof(char) * 20);
char* pstar = strchr(buffer, '*'); char buffer[BufferSize] = {};
if (nullptr == pstar) stream->read((char *)&diffuse, sizeof(float) * 4);
{ stream->read((char *)&power, sizeof(float));
stream->read((char *)&specular, sizeof(float) * 3);
stream->read((char *)&ambient, sizeof(float) * 3);
stream->read((char *)&toon_index, sizeof(uint8_t));
stream->read((char *)&edge_flag, sizeof(uint8_t));
stream->read((char *)&index_count, sizeof(uint32_t));
stream->read((char *)&buffer, sizeof(char) * BufferSize);
char *pstar = strchr(buffer, '*');
if (nullptr == pstar) {
texture_filename = std::string(buffer); texture_filename = std::string(buffer);
sphere_filename.clear(); sphere_filename.clear();
} } else {
else {
*pstar = 0; *pstar = 0;
texture_filename = std::string(buffer); texture_filename = std::string(buffer);
sphere_filename = std::string(pstar+1); sphere_filename = std::string(pstar + 1);
} }
return true; return true;
} }
}; };
enum class BoneType : uint8_t enum class BoneType : uint8_t {
{
Rotation, Rotation,
RotationAndMove, RotationAndMove,
IkEffector, IkEffector,
@ -157,11 +169,10 @@ namespace pmd
Invisible, Invisible,
Twist, Twist,
RotationMovement RotationMovement
};
class PmdBone };
{
public: struct PmdBone {
std::string name; std::string name;
std::string name_english; std::string name_english;
uint16_t parent_bone_index; uint16_t parent_bone_index;
@ -170,155 +181,192 @@ namespace pmd
uint16_t ik_parent_bone_index; uint16_t ik_parent_bone_index;
float bone_head_pos[3]; float bone_head_pos[3];
void Read(std::istream *stream) PmdBone() :
{ name(), name_english(), parent_bone_index(0), tail_pos_bone_index(0), bone_type(BoneType::Unknown), ik_parent_bone_index(0), bone_head_pos{ 0.0f } {}
char buffer[20];
stream->read(buffer, 20); ~PmdBone() = default;
void Read(std::istream *stream) {
if (stream == nullptr) {
return;
}
constexpr size_t BufferSize = 20;
char buffer[BufferSize] = {};
stream->read(buffer, BufferSize);
name = std::string(buffer); name = std::string(buffer);
stream->read((char*) &parent_bone_index, sizeof(uint16_t)); stream->read((char *)&parent_bone_index, sizeof(uint16_t));
stream->read((char*) &tail_pos_bone_index, sizeof(uint16_t)); stream->read((char *)&tail_pos_bone_index, sizeof(uint16_t));
stream->read((char*) &bone_type, sizeof(uint8_t)); stream->read((char *)&bone_type, sizeof(uint8_t));
stream->read((char*) &ik_parent_bone_index, sizeof(uint16_t)); stream->read((char *)&ik_parent_bone_index, sizeof(uint16_t));
stream->read((char*) &bone_head_pos, sizeof(float) * 3); stream->read((char *)&bone_head_pos, sizeof(float) * 3);
} }
void ReadExpantion(std::istream *stream) void ReadExpantion(std::istream *stream) {
{ if (stream == nullptr) {
char buffer[20]; return;
stream->read(buffer, 20); }
constexpr size_t BufferSize = 20;
char buffer[BufferSize] = {};
stream->read(buffer, BufferSize);
name_english = std::string(buffer); name_english = std::string(buffer);
} }
}; };
class PmdIk struct PmdIk {
{
public:
uint16_t ik_bone_index; uint16_t ik_bone_index;
uint16_t target_bone_index; uint16_t target_bone_index;
uint16_t iterations; uint16_t iterations;
float angle_limit; float angle_limit;
std::vector<uint16_t> ik_child_bone_index; std::vector<uint16_t> ik_child_bone_index;
void Read(std::istream *stream) PmdIk() :
{ ik_child_bone_index(0), target_bone_index(0), iterations(0), angle_limit(0.0f) {}
stream->read((char *) &ik_bone_index, sizeof(uint16_t));
stream->read((char *) &target_bone_index, sizeof(uint16_t));
uint8_t ik_chain_length;
stream->read((char*) &ik_chain_length, sizeof(uint8_t));
stream->read((char *) &iterations, sizeof(uint16_t));
stream->read((char *) &angle_limit, sizeof(float));
ik_child_bone_index.resize(ik_chain_length);
for (int i = 0; i < ik_chain_length; i++)
{
stream->read((char *) &ik_child_bone_index[i], sizeof(uint16_t));
}
}
};
class PmdFaceVertex ~PmdIk() = default;
{
public: void Read(std::istream *stream) {
if (stream == nullptr) {
return;
}
stream->read((char *)&ik_bone_index, sizeof(uint16_t));
stream->read((char *)&target_bone_index, sizeof(uint16_t));
uint8_t ik_chain_length;
stream->read((char *)&ik_chain_length, sizeof(uint8_t));
stream->read((char *)&iterations, sizeof(uint16_t));
stream->read((char *)&angle_limit, sizeof(float));
ik_child_bone_index.resize(ik_chain_length);
for (int i = 0; i < ik_chain_length; i++) {
stream->read((char *)&ik_child_bone_index[i], sizeof(uint16_t));
}
}
};
struct PmdFaceVertex {
int vertex_index; int vertex_index;
float position[3]; float position[3];
void Read(std::istream *stream) PmdFaceVertex() :
{ vertex_index(0), position{ 0.0f } {}
stream->read((char *) &vertex_index, sizeof(int));
stream->read((char *) position, sizeof(float) * 3);
}
};
enum class FaceCategory : uint8_t ~PmdFaceVertex() = default;
{
void Read(std::istream *stream) {
if (stream == nullptr) {
return;
}
stream->read((char *)&vertex_index, sizeof(int));
stream->read((char *)position, sizeof(float) * 3);
}
};
enum class FaceCategory : uint8_t {
Base, Base,
Eyebrow, Eyebrow,
Eye, Eye,
Mouth, Mouth,
Other Other
}; };
class PmdFace struct PmdFace {
{
public:
std::string name; std::string name;
FaceCategory type; FaceCategory type;
std::vector<PmdFaceVertex> vertices; std::vector<PmdFaceVertex> vertices;
std::string name_english; std::string name_english;
void Read(std::istream *stream) PmdFace() :
{ name(), type(FaceCategory::Other), vertices(), name_english() {}
char buffer[20];
stream->read(buffer, 20); ~PmdFace() = default;
void Read(std::istream *stream) {
if (stream == nullptr) {
return;
}
constexpr size_t BufferSize = 20;
char buffer[BufferSize];
stream->read(buffer, BufferSize);
name = std::string(buffer); name = std::string(buffer);
int vertex_count; int vertex_count;
stream->read((char*) &vertex_count, sizeof(int)); stream->read((char *)&vertex_count, sizeof(int));
stream->read((char*) &type, sizeof(uint8_t)); stream->read((char *)&type, sizeof(uint8_t));
vertices.resize(vertex_count); vertices.resize(vertex_count);
for (int i = 0; i < vertex_count; i++) for (int i = 0; i < vertex_count; i++) {
{
vertices[i].Read(stream); vertices[i].Read(stream);
} }
} }
void ReadExpantion(std::istream *stream) void ReadExpantion(std::istream *stream) {
{ if (stream == nullptr) {
return;
}
char buffer[20]; char buffer[20];
stream->read(buffer, 20); stream->read(buffer, 20);
name_english = std::string(buffer); name_english = std::string(buffer);
} }
}; };
class PmdBoneDispName struct PmdBoneDispName {
{
public:
std::string bone_disp_name; std::string bone_disp_name;
std::string bone_disp_name_english; std::string bone_disp_name_english;
void Read(std::istream *stream) PmdBoneDispName() = default;
{
~PmdBoneDispName() = default;
void Read(std::istream *stream) {
if (stream == nullptr) {
return;
}
char buffer[50]; char buffer[50];
stream->read(buffer, 50); stream->read(buffer, 50);
bone_disp_name = std::string(buffer); bone_disp_name = std::string(buffer);
bone_disp_name_english.clear(); bone_disp_name_english.clear();
} }
void ReadExpantion(std::istream *stream)
{ void ReadExpantion(std::istream *stream) {
if (stream == nullptr) {
return;
}
char buffer[50]; char buffer[50];
stream->read(buffer, 50); stream->read(buffer, 50);
bone_disp_name_english = std::string(buffer); bone_disp_name_english = std::string(buffer);
} }
}; };
class PmdBoneDisp struct PmdBoneDisp {
{
public:
uint16_t bone_index; uint16_t bone_index;
uint8_t bone_disp_index; uint8_t bone_disp_index;
void Read(std::istream *stream) PmdBoneDisp() :
{ bone_index(0), bone_disp_index(0) {}
stream->read((char*) &bone_index, sizeof(uint16_t));
stream->read((char*) &bone_disp_index, sizeof(uint8_t));
}
};
enum class RigidBodyShape : uint8_t ~PmdBoneDisp() = default;
{
void Read(std::istream *stream) {
if (stream == nullptr) {
return;
}
stream->read((char *)&bone_index, sizeof(uint16_t));
stream->read((char *)&bone_disp_index, sizeof(uint8_t));
}
};
enum class RigidBodyShape : uint8_t {
Sphere = 0, Sphere = 0,
Box = 1, Box = 1,
Cpusel = 2 Cpusel = 2
}; };
enum class RigidBodyType : uint8_t enum class RigidBodyType : uint8_t {
{
BoneConnected = 0, BoneConnected = 0,
Physics = 1, Physics = 1,
ConnectedPhysics = 2 ConnectedPhysics = 2
}; };
class PmdRigidBody struct PmdRigidBody {
{
public:
std::string name; std::string name;
uint16_t related_bone_index; uint16_t related_bone_index;
uint8_t group_index; uint8_t group_index;
@ -334,30 +382,36 @@ namespace pmd
float friction; float friction;
RigidBodyType rigid_type; RigidBodyType rigid_type;
void Read(std::istream *stream) PmdRigidBody() :
{ name(), related_bone_index(0), group_index(0), mask(0), shape(RigidBodyShape::Box), size{ 0.0f }, position{ 0.0f }, weight(0.0f), linear_damping(0.0f), anglar_damping(0.0f), restitution(0.0f), friction(0.0f), rigid_type(RigidBodyType::BoneConnected) {}
~PmdRigidBody() = default;
void Read(std::istream *stream) {
if (stream == nullptr) {
return;
}
char buffer[20]; char buffer[20];
stream->read(buffer, sizeof(char) * 20); stream->read(buffer, sizeof(char) * 20);
name = (std::string(buffer)); name = (std::string(buffer));
stream->read((char*) &related_bone_index, sizeof(uint16_t)); stream->read((char *)&related_bone_index, sizeof(uint16_t));
stream->read((char*) &group_index, sizeof(uint8_t)); stream->read((char *)&group_index, sizeof(uint8_t));
stream->read((char*) &mask, sizeof(uint16_t)); stream->read((char *)&mask, sizeof(uint16_t));
stream->read((char*) &shape, sizeof(uint8_t)); stream->read((char *)&shape, sizeof(uint8_t));
stream->read((char*) size, sizeof(float) * 3); stream->read((char *)size, sizeof(float) * 3);
stream->read((char*) position, sizeof(float) * 3); stream->read((char *)position, sizeof(float) * 3);
stream->read((char*) orientation, sizeof(float) * 3); stream->read((char *)orientation, sizeof(float) * 3);
stream->read((char*) &weight, sizeof(float)); stream->read((char *)&weight, sizeof(float));
stream->read((char*) &linear_damping, sizeof(float)); stream->read((char *)&linear_damping, sizeof(float));
stream->read((char*) &anglar_damping, sizeof(float)); stream->read((char *)&anglar_damping, sizeof(float));
stream->read((char*) &restitution, sizeof(float)); stream->read((char *)&restitution, sizeof(float));
stream->read((char*) &friction, sizeof(float)); stream->read((char *)&friction, sizeof(float));
stream->read((char*) &rigid_type, sizeof(char)); stream->read((char *)&rigid_type, sizeof(char));
} }
}; };
class PmdConstraint struct PmdConstraint {
{
public:
std::string name; std::string name;
uint32_t rigid_body_index_a; uint32_t rigid_body_index_a;
uint32_t rigid_body_index_b; uint32_t rigid_body_index_b;
@ -370,27 +424,33 @@ namespace pmd
float linear_stiffness[3]; float linear_stiffness[3];
float angular_stiffness[3]; float angular_stiffness[3];
void Read(std::istream *stream) PmdConstraint() :
{ name(), rigid_body_index_a(0), rigid_body_index_b(0), position{ 0.0f }, orientation{ 0.0f }, linear_lower_limit{ 0.0f }, linear_upper_limit{ 0.0f }, angular_lower_limit{ 0.0f }, angular_upper_limit{ 0.0f }, linear_stiffness{ 0.0f }, angular_stiffness{ 0.0f } {}
~PmdConstraint() = default;
void Read(std::istream *stream) {
if (stream == nullptr) {
return;
}
char buffer[20]; char buffer[20];
stream->read(buffer, 20); stream->read(buffer, 20);
name = std::string(buffer); name = std::string(buffer);
stream->read((char *) &rigid_body_index_a, sizeof(uint32_t)); stream->read((char *)&rigid_body_index_a, sizeof(uint32_t));
stream->read((char *) &rigid_body_index_b, sizeof(uint32_t)); stream->read((char *)&rigid_body_index_b, sizeof(uint32_t));
stream->read((char *) position, sizeof(float) * 3); stream->read((char *)position, sizeof(float) * 3);
stream->read((char *) orientation, sizeof(float) * 3); stream->read((char *)orientation, sizeof(float) * 3);
stream->read((char *) linear_lower_limit, sizeof(float) * 3); stream->read((char *)linear_lower_limit, sizeof(float) * 3);
stream->read((char *) linear_upper_limit, sizeof(float) * 3); stream->read((char *)linear_upper_limit, sizeof(float) * 3);
stream->read((char *) angular_lower_limit, sizeof(float) * 3); stream->read((char *)angular_lower_limit, sizeof(float) * 3);
stream->read((char *) angular_upper_limit, sizeof(float) * 3); stream->read((char *)angular_upper_limit, sizeof(float) * 3);
stream->read((char *) linear_stiffness, sizeof(float) * 3); stream->read((char *)linear_stiffness, sizeof(float) * 3);
stream->read((char *) angular_stiffness, sizeof(float) * 3); stream->read((char *)angular_stiffness, sizeof(float) * 3);
} }
}; };
class PmdModel struct PmdModel {
{
public:
float version; float version;
PmdHeader header; PmdHeader header;
std::vector<PmdVertex> vertices; std::vector<PmdVertex> vertices;
@ -406,11 +466,18 @@ namespace pmd
std::vector<PmdRigidBody> rigid_bodies; std::vector<PmdRigidBody> rigid_bodies;
std::vector<PmdConstraint> constraints; std::vector<PmdConstraint> constraints;
static std::unique_ptr<PmdModel> LoadFromFile(const char *filename) PmdModel() :
{ version(0.0f) {}
~PmdModel() = default;
static std::unique_ptr<PmdModel> LoadFromFile(const char *filename) {
if (filename == nullptr) {
return nullptr;
}
std::ifstream stream(filename, std::ios::binary); std::ifstream stream(filename, std::ios::binary);
if (stream.fail()) if (stream.fail()) {
{
std::cerr << "could not open \"" << filename << "\"" << std::endl; std::cerr << "could not open \"" << filename << "\"" << std::endl;
return nullptr; return nullptr;
} }
@ -419,24 +486,21 @@ namespace pmd
return result; return result;
} }
static std::unique_ptr<PmdModel> LoadFromStream(std::ifstream *stream) static std::unique_ptr<PmdModel> LoadFromStream(std::ifstream *stream) {
{
auto result = mmd::make_unique<PmdModel>(); auto result = mmd::make_unique<PmdModel>();
char buffer[100]; char buffer[100];
// magic // magic
char magic[3]; char magic[3];
stream->read(magic, 3); stream->read(magic, 3);
if (magic[0] != 'P' || magic[1] != 'm' || magic[2] != 'd') if (magic[0] != 'P' || magic[1] != 'm' || magic[2] != 'd') {
{
std::cerr << "invalid file" << std::endl; std::cerr << "invalid file" << std::endl;
return nullptr; return nullptr;
} }
// version // version
stream->read((char*) &(result->version), sizeof(float)); stream->read((char *)&(result->version), sizeof(float));
if (result ->version != 1.0f) if (result->version != 1.0f) {
{
std::cerr << "invalid version" << std::endl; std::cerr << "invalid version" << std::endl;
return nullptr; return nullptr;
} }
@ -446,152 +510,132 @@ namespace pmd
// vertices // vertices
uint32_t vertex_num; uint32_t vertex_num;
stream->read((char*) &vertex_num, sizeof(uint32_t)); stream->read((char *)&vertex_num, sizeof(uint32_t));
result->vertices.resize(vertex_num); result->vertices.resize(vertex_num);
for (uint32_t i = 0; i < vertex_num; i++) for (uint32_t i = 0; i < vertex_num; i++) {
{
result->vertices[i].Read(stream); result->vertices[i].Read(stream);
} }
// indices // indices
uint32_t index_num; uint32_t index_num;
stream->read((char*) &index_num, sizeof(uint32_t)); stream->read((char *)&index_num, sizeof(uint32_t));
result->indices.resize(index_num); result->indices.resize(index_num);
for (uint32_t i = 0; i < index_num; i++) for (uint32_t i = 0; i < index_num; i++) {
{ stream->read((char *)&result->indices[i], sizeof(uint16_t));
stream->read((char*) &result->indices[i], sizeof(uint16_t));
} }
// materials // materials
uint32_t material_num; uint32_t material_num;
stream->read((char*) &material_num, sizeof(uint32_t)); stream->read((char *)&material_num, sizeof(uint32_t));
result->materials.resize(material_num); result->materials.resize(material_num);
for (uint32_t i = 0; i < material_num; i++) for (uint32_t i = 0; i < material_num; i++) {
{
result->materials[i].Read(stream); result->materials[i].Read(stream);
} }
// bones // bones
uint16_t bone_num; uint16_t bone_num;
stream->read((char*) &bone_num, sizeof(uint16_t)); stream->read((char *)&bone_num, sizeof(uint16_t));
result->bones.resize(bone_num); result->bones.resize(bone_num);
for (uint32_t i = 0; i < bone_num; i++) for (uint32_t i = 0; i < bone_num; i++) {
{
result->bones[i].Read(stream); result->bones[i].Read(stream);
} }
// iks // iks
uint16_t ik_num; uint16_t ik_num;
stream->read((char*) &ik_num, sizeof(uint16_t)); stream->read((char *)&ik_num, sizeof(uint16_t));
result->iks.resize(ik_num); result->iks.resize(ik_num);
for (uint32_t i = 0; i < ik_num; i++) for (uint32_t i = 0; i < ik_num; i++) {
{
result->iks[i].Read(stream); result->iks[i].Read(stream);
} }
// faces // faces
uint16_t face_num; uint16_t face_num;
stream->read((char*) &face_num, sizeof(uint16_t)); stream->read((char *)&face_num, sizeof(uint16_t));
result->faces.resize(face_num); result->faces.resize(face_num);
for (uint32_t i = 0; i < face_num; i++) for (uint32_t i = 0; i < face_num; i++) {
{
result->faces[i].Read(stream); result->faces[i].Read(stream);
} }
// face frames // face frames
uint8_t face_frame_num; uint8_t face_frame_num;
stream->read((char*) &face_frame_num, sizeof(uint8_t)); stream->read((char *)&face_frame_num, sizeof(uint8_t));
result->faces_indices.resize(face_frame_num); result->faces_indices.resize(face_frame_num);
for (uint32_t i = 0; i < face_frame_num; i++) for (uint32_t i = 0; i < face_frame_num; i++) {
{ stream->read((char *)&result->faces_indices[i], sizeof(uint16_t));
stream->read((char*) &result->faces_indices[i], sizeof(uint16_t));
} }
// bone names // bone names
uint8_t bone_disp_num; uint8_t bone_disp_num;
stream->read((char*) &bone_disp_num, sizeof(uint8_t)); stream->read((char *)&bone_disp_num, sizeof(uint8_t));
result->bone_disp_name.resize(bone_disp_num); result->bone_disp_name.resize(bone_disp_num);
for (uint32_t i = 0; i < bone_disp_num; i++) for (uint32_t i = 0; i < bone_disp_num; i++) {
{
result->bone_disp_name[i].Read(stream); result->bone_disp_name[i].Read(stream);
} }
// bone frame // bone frame
uint32_t bone_frame_num; uint32_t bone_frame_num;
stream->read((char*) &bone_frame_num, sizeof(uint32_t)); stream->read((char *)&bone_frame_num, sizeof(uint32_t));
result->bone_disp.resize(bone_frame_num); result->bone_disp.resize(bone_frame_num);
for (uint32_t i = 0; i < bone_frame_num; i++) for (uint32_t i = 0; i < bone_frame_num; i++) {
{
result->bone_disp[i].Read(stream); result->bone_disp[i].Read(stream);
} }
// english name // english name
bool english; bool english;
stream->read((char*) &english, sizeof(char)); stream->read((char *)&english, sizeof(char));
if (english) if (english) {
{
result->header.ReadExtension(stream); result->header.ReadExtension(stream);
for (uint32_t i = 0; i < bone_num; i++) for (uint32_t i = 0; i < bone_num; i++) {
{
result->bones[i].ReadExpantion(stream); result->bones[i].ReadExpantion(stream);
} }
for (uint32_t i = 0; i < face_num; i++) for (uint32_t i = 0; i < face_num; i++) {
{ if (result->faces[i].type == pmd::FaceCategory::Base) {
if (result->faces[i].type == pmd::FaceCategory::Base)
{
continue; continue;
} }
result->faces[i].ReadExpantion(stream); result->faces[i].ReadExpantion(stream);
} }
for (uint32_t i = 0; i < result->bone_disp_name.size(); i++) for (uint32_t i = 0; i < result->bone_disp_name.size(); i++) {
{
result->bone_disp_name[i].ReadExpantion(stream); result->bone_disp_name[i].ReadExpantion(stream);
} }
} }
// toon textures // toon textures
if (stream->peek() == std::ios::traits_type::eof()) if (stream->peek() == std::ios::traits_type::eof()) {
{
result->toon_filenames.clear(); result->toon_filenames.clear();
} } else {
else {
result->toon_filenames.resize(10); result->toon_filenames.resize(10);
for (uint32_t i = 0; i < 10; i++) for (uint32_t i = 0; i < 10; i++) {
{
stream->read(buffer, 100); stream->read(buffer, 100);
result->toon_filenames[i] = std::string(buffer); result->toon_filenames[i] = std::string(buffer);
} }
} }
// physics // physics
if (stream->peek() == std::ios::traits_type::eof()) if (stream->peek() == std::ios::traits_type::eof()) {
{
result->rigid_bodies.clear(); result->rigid_bodies.clear();
result->constraints.clear(); result->constraints.clear();
} } else {
else {
uint32_t rigid_body_num; uint32_t rigid_body_num;
stream->read((char*) &rigid_body_num, sizeof(uint32_t)); stream->read((char *)&rigid_body_num, sizeof(uint32_t));
result->rigid_bodies.resize(rigid_body_num); result->rigid_bodies.resize(rigid_body_num);
for (uint32_t i = 0; i < rigid_body_num; i++) for (uint32_t i = 0; i < rigid_body_num; i++) {
{
result->rigid_bodies[i].Read(stream); result->rigid_bodies[i].Read(stream);
} }
uint32_t constraint_num; uint32_t constraint_num;
stream->read((char*) &constraint_num, sizeof(uint32_t)); stream->read((char *)&constraint_num, sizeof(uint32_t));
result->constraints.resize(constraint_num); result->constraints.resize(constraint_num);
for (uint32_t i = 0; i < constraint_num; i++) for (uint32_t i = 0; i < constraint_num; i++) {
{
result->constraints[i].Read(stream); result->constraints[i].Read(stream);
} }
} }
if (stream->peek() != std::ios::traits_type::eof()) if (stream->peek() != std::ios::traits_type::eof()) {
{
std::cerr << "there is unknown data" << std::endl; std::cerr << "there is unknown data" << std::endl;
} }
return result; return result;
} }
}; };
}
} // namespace pmd

View File

@ -46,7 +46,7 @@ namespace Assimp {
namespace Base64 { namespace Base64 {
static const uint8_t tableDecodeBase64[128] = { static constexpr uint8_t tableDecodeBase64[128] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
@ -57,7 +57,7 @@ static const uint8_t tableDecodeBase64[128] = {
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0
}; };
static const char *tableEncodeBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; static constexpr char *tableEncodeBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
static inline char EncodeChar(uint8_t b) { static inline char EncodeChar(uint8_t b) {
return tableEncodeBase64[size_t(b)]; return tableEncodeBase64[size_t(b)];
@ -71,6 +71,11 @@ inline uint8_t DecodeChar(char c) {
} }
void Encode(const uint8_t *in, size_t inLength, std::string &out) { void Encode(const uint8_t *in, size_t inLength, std::string &out) {
if (in == nullptr || inLength==0) {
out.clear();
return;
}
size_t outLength = ((inLength + 2) / 3) * 4; size_t outLength = ((inLength + 2) / 3) * 4;
size_t j = out.size(); size_t j = out.size();
@ -115,8 +120,14 @@ std::string Encode(const std::vector<uint8_t> &in) {
} }
size_t Decode(const char *in, size_t inLength, uint8_t *&out) { size_t Decode(const char *in, size_t inLength, uint8_t *&out) {
if (in == nullptr) {
out = nullptr;
return 0;
}
if (inLength % 4 != 0) { if (inLength % 4 != 0) {
throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)), "\", length:", inLength); throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)),
"\", length:", inLength);
} }
if (inLength < 4) { if (inLength < 4) {

View File

@ -50,16 +50,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace Base64 { namespace Base64 {
/// @brief Will encode the given /// @brief Will encode the given character buffer from UTF64 to ASCII
/// @param in /// @param in The UTF-64 buffer.
/// @param inLength /// @param inLength The size of the buffer
/// @param out /// @param out The encoded ASCII string.
void Encode(const uint8_t *in, size_t inLength, std::string &out); void Encode(const uint8_t *in, size_t inLength, std::string &out);
/// @brief Will encode the given character buffer from UTF64 to ASCII.
/// @param in A vector, which contains the buffer for encoding.
/// @param out The encoded ASCII string.
void Encode(const std::vector<uint8_t>& in, std::string &out); void Encode(const std::vector<uint8_t>& in, std::string &out);
/// @brief Will encode the given character buffer from UTF64 to ASCII.
/// @param in A vector, which contains the buffer for encoding.
/// @return The encoded ASCII string.
std::string Encode(const std::vector<uint8_t>& in); std::string Encode(const std::vector<uint8_t>& in);
/// @brief Will decode the given character buffer from ASCII to UTF64.
/// @param in The ASCII buffer to decode.
/// @param inLength The size of the buffer.
/// @param out The decoded buffer.
/// @return The new buffer size.
size_t Decode(const char *in, size_t inLength, uint8_t *&out); size_t Decode(const char *in, size_t inLength, uint8_t *&out);
/// @brief Will decode the given character buffer from ASCII to UTF64.
/// @param in The ASCII buffer to decode as a std::string.
/// @param out The decoded buffer.
/// @return The new buffer size.
size_t Decode(const std::string& in, std::vector<uint8_t>& out); size_t Decode(const std::string& in, std::vector<uint8_t>& out);
/// @brief Will decode the given character buffer from ASCII to UTF64.
/// @param in The ASCII string.
/// @return The decoded buffer in a vector.
std::vector<uint8_t> Decode(const std::string& in); std::vector<uint8_t> Decode(const std::string& in);
} // namespace Base64 } // namespace Base64

View File

@ -47,26 +47,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace std; using namespace std;
using namespace Assimp; using namespace Assimp;
class Base64Test : public ::testing::Test { class Base64Test : public ::testing::Test {};
public:
virtual void SetUp() {
}
virtual void TearDown() {
}
};
static const std::vector<uint8_t> assimpStringBinary = { 97, 115, 115, 105, 109, 112 }; static const std::vector<uint8_t> assimpStringBinary = { 97, 115, 115, 105, 109, 112 };
static const std::string assimpStringEncoded = "YXNzaW1w"; static const std::string assimpStringEncoded = "YXNzaW1w";
TEST_F( Base64Test, encodeTest ) { TEST_F( Base64Test, encodeTest) {
EXPECT_EQ( "", Base64::Encode (std::vector<uint8_t>{}) ); EXPECT_EQ( "", Base64::Encode(std::vector<uint8_t>{}) );
EXPECT_EQ( "Vg==", Base64::Encode (std::vector<uint8_t>{ 86 }) ); EXPECT_EQ( "Vg==", Base64::Encode(std::vector<uint8_t>{ 86 }) );
EXPECT_EQ( assimpStringEncoded, Base64::Encode (assimpStringBinary) ); EXPECT_EQ( assimpStringEncoded, Base64::Encode(assimpStringBinary) );
} }
TEST_F( Base64Test, decodeTest ) { TEST_F( Base64Test, encodeTestWithNullptr ) {
EXPECT_EQ( std::vector<uint8_t> {}, Base64::Decode ("") ); std::string out;
EXPECT_EQ( std::vector<uint8_t> { 86 }, Base64::Decode ("Vg==") ); Base64::Encode(nullptr, 100u, out);
EXPECT_EQ( assimpStringBinary, Base64::Decode (assimpStringEncoded) ); EXPECT_TRUE(out.empty());
Base64::Encode(&assimpStringBinary[0], 0u, out);
EXPECT_TRUE(out.empty());
}
TEST_F( Base64Test, decodeTest) {
EXPECT_EQ( std::vector<uint8_t> {}, Base64::Decode("") );
EXPECT_EQ( std::vector<uint8_t> { 86 }, Base64::Decode("Vg==") );
EXPECT_EQ( assimpStringBinary, Base64::Decode(assimpStringEncoded) );
}
TEST_F(Base64Test, decodeTestWithNullptr) {
uint8_t *out = nullptr;
size_t size = Base64::Decode(nullptr, 100u, out);
EXPECT_EQ(nullptr, out);
EXPECT_EQ(0u, size);
} }