using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using MMD.PMX;
using MMD.PMD;
	
public partial class PMXLoaderScript {

	/// <summary>
	/// PMXファイルのヘッダー取得
	/// </summary>
	/// <param name='file_path'>PMDファイルのパス</param>
	/// <returns>ヘッダー</returns>
	public static PMDFormat.Header GetHeader(string file_path) {
		PMXLoaderScript loader = new PMXLoaderScript();
		PMXFormat.Header pmx_header = loader.GetHeader_(file_path);
		return PMX2PMD(pmx_header);
	}

	/// <summary>
	/// PMXファイルのインポート
	/// </summary>
	/// <param name='file_path'>PMDファイルのパス</param>
	/// <returns>内部形式データ</returns>
	public static PMDFormat Import(string file_path) {
		PMXLoaderScript loader = new PMXLoaderScript();
		PMXFormat pmx = loader.Import_(file_path);
		return PMX2PMD(pmx);
	}

	/// <summary>
	/// デフォルトコンストラクタ
	/// </summary>
	/// <remarks>
	/// ユーザーに依るインスタンス作成を禁止する
	/// </remarks>
	private PMXLoaderScript() {}

	private PMXFormat.Header GetHeader_(string file_path) {
		PMXFormat.Header result;
		using (FileStream stream = new FileStream(file_path, FileMode.Open, FileAccess.Read))
		using (BinaryReader bin = new BinaryReader(stream)) {
			file_path_ = null;
			binary_reader_ = bin;
			result = ReadHeader();
		}
		return result;
	}

	private PMXFormat Import_(string file_path) {
		using (FileStream stream = new FileStream(file_path, FileMode.Open, FileAccess.Read))
		using (BinaryReader bin = new BinaryReader(stream)) {
			file_path_ = file_path;
			binary_reader_ = bin;
			Read();
		}
		return format_;
	}

	private PMXFormat Read() {
		format_ = new PMXFormat();
		format_.meta_header = CreateMetaHeader();
		format_.head = ReadHeader();
		format_.vertex_list = ReadVertexList();
		format_.face_vertex_list = ReadFaceVertexList();
		format_.texture_list = ReadTextureList();
		format_.material_list = ReadMaterialList();
		format_.bone_list = ReadBoneList(); 
		format_.morph_list = ReadMorphList();
		format_.display_frame_list = ReadDisplayFrameList();
		format_.rigidbody_list = ReadRigidbodyList();
		format_.rigidbody_joint_list = ReadRigidbodyJointList();
		return format_;
	}

	private PMXFormat.MetaHeader CreateMetaHeader() {
		PMXFormat.MetaHeader result = new PMXFormat.MetaHeader();
		result.path = file_path_;
		result.name = Path.GetFileNameWithoutExtension(file_path_); // .pmdを抜かす
		result.folder = Path.GetDirectoryName(file_path_); // PMDが格納されているフォルダ
		return result;
	}
	
	private PMXFormat.Header ReadHeader() {
		PMXFormat.Header result = new PMXFormat.Header();
		result.magic = binary_reader_.ReadBytes(4);
		if (Encoding.ASCII.GetString(result.magic) != "PMX ") {
			throw new System.FormatException();
		}
		result.version = binary_reader_.ReadSingle();
		binary_reader_.ReadByte();
		result.encodeMethod = binary_reader_.ReadByte();
		result.additionalUV = binary_reader_.ReadByte();
		result.vertexIndexSize = binary_reader_.ReadByte();
		result.textureIndexSize = binary_reader_.ReadByte();
		result.materialIndexSize = binary_reader_.ReadByte();
		result.boneIndexSize = binary_reader_.ReadByte();
		result.morphIndexSize = binary_reader_.ReadByte();
		result.rigidbodyIndexSize = binary_reader_.ReadByte();
		
		this.string_code_ = (StringCode)result.encodeMethod;
		result.model_name = ReadString();
		result.model_english_name = ReadString();
		result.comment = ReadString();
		result.english_comment = ReadString();

		return result;
	}

	private PMXFormat.VertexList ReadVertexList() {
		PMXFormat.VertexList result = new PMXFormat.VertexList();
		result.vert_count = binary_reader_.ReadUInt32();
		result.vertex = new PMXFormat.Vertex[result.vert_count];
		for (int i = 0; i < result.vert_count; i++) {
			result.vertex[i] = ReadVertex();
		}
		return result;
	}

	private PMXFormat.Vertex ReadVertex() {
		PMXFormat.Vertex result = new PMXFormat.Vertex();
		result.pos = ReadSinglesToVector3(binary_reader_);
		result.normal_vec = ReadSinglesToVector3(binary_reader_);
		result.uv = ReadSinglesToVector2(binary_reader_);
		result.add_uv = new Quaternion[format_.head.additionalUV];
		for (int i = 0; i < format_.head.additionalUV; i++) {
			result.add_uv[i] = ReadSinglesToQuaternion(binary_reader_);
		}
		result.weight_method = (PMXFormat.Vertex.WeightMethod)binary_reader_.ReadByte();
		switch(result.weight_method) {
		case PMXFormat.Vertex.WeightMethod.BDEF1:
			result.bone_weight = ReadBoneWeightBDEF1();
			break;
		case PMXFormat.Vertex.WeightMethod.BDEF2:
			result.bone_weight = ReadBoneWeightBDEF2();
			break;
		case PMXFormat.Vertex.WeightMethod.BDEF4:
			result.bone_weight = ReadBoneWeightBDEF4();
			break;
		case PMXFormat.Vertex.WeightMethod.SDEF:
			result.bone_weight = ReadBoneWeightSDEF();
			break;
		case PMXFormat.Vertex.WeightMethod.QDEF:
			result.bone_weight = ReadBoneWeightQDEF();
			break;
		default:
			result.bone_weight = null;
			throw new System.FormatException();
		}
		result.edge_magnification = binary_reader_.ReadSingle();
		return result;
	}

	private PMXFormat.BoneWeight ReadBoneWeightBDEF1() {
		PMXFormat.BDEF1 result = new PMXFormat.BDEF1();
		result.bone1_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		return result;
	}
	private PMXFormat.BoneWeight ReadBoneWeightBDEF2() {
		PMXFormat.BDEF2 result = new PMXFormat.BDEF2();
		result.bone1_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone2_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone1_weight = binary_reader_.ReadSingle();
		return result;
	}
	private PMXFormat.BoneWeight ReadBoneWeightBDEF4() {
		PMXFormat.BDEF4 result = new PMXFormat.BDEF4();
		result.bone1_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone2_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone3_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone4_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone1_weight = binary_reader_.ReadSingle();
		result.bone2_weight = binary_reader_.ReadSingle();
		result.bone3_weight = binary_reader_.ReadSingle();
		result.bone4_weight = binary_reader_.ReadSingle();
		return result;
	}
	private PMXFormat.BoneWeight ReadBoneWeightSDEF() {
		PMXFormat.SDEF result = new PMXFormat.SDEF();
		result.bone1_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone2_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone1_weight = binary_reader_.ReadSingle();
		result.c_value = ReadSinglesToVector3(binary_reader_);
		result.r0_value = ReadSinglesToVector3(binary_reader_);
		result.r1_value = ReadSinglesToVector3(binary_reader_);
		return result;
	}
	private PMXFormat.BoneWeight ReadBoneWeightQDEF() {
		PMXFormat.BDEF4 result = new PMXFormat.BDEF4();
		result.bone1_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone2_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone3_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone4_ref = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.bone1_weight = binary_reader_.ReadSingle();
		result.bone2_weight = binary_reader_.ReadSingle();
		result.bone3_weight = binary_reader_.ReadSingle();
		result.bone4_weight = binary_reader_.ReadSingle();
		return result;
	}
	
	private PMXFormat.FaceVertexList ReadFaceVertexList() {
		PMXFormat.FaceVertexList result = new PMXFormat.FaceVertexList();
		result.face_vert_count = binary_reader_.ReadUInt32();
		result.face_vert_index = new uint[result.face_vert_count];
		for (uint i = 0; i < result.face_vert_count; i++) {
			result.face_vert_index[i] = CastIntRead(binary_reader_, format_.head.vertexIndexSize);
		}
		return result;
	}

	private PMXFormat.TextureList ReadTextureList() {
		PMXFormat.TextureList result = new PMXFormat.TextureList();
		result.texture_file_count = binary_reader_.ReadUInt32();
		result.texture_file = new string[result.texture_file_count];
		for (uint i = 0; i < result.texture_file_count; i++) {
			result.texture_file[i] = ReadString();
		}
		return result;
	}

	private PMXFormat.MaterialList ReadMaterialList() {
		PMXFormat.MaterialList result = new PMXFormat.MaterialList();
		result.material_count = binary_reader_.ReadUInt32();
		result.material = new PMXFormat.Material[result.material_count];
		for (int i = 0; i < result.material_count; i++) {
			result.material[i] = ReadMaterial();
		}
		return result;
	}
	
	private PMXFormat.Material ReadMaterial() {
		PMXFormat.Material result = new PMXFormat.Material();
		result.name = ReadString();
		result.english_name = ReadString();
		result.diffuse_color = ReadSinglesToColor(binary_reader_); // dr, dg, db, da // 減衰色
		result.specular_color = ReadSinglesToColor(binary_reader_, 1); // sr, sg, sb // 光沢色
		result.specularity = binary_reader_.ReadSingle();
		result.ambient_color = ReadSinglesToColor(binary_reader_, 1); // mr, mg, mb // 環境色(ambient)
		result.flag = (PMXFormat.Material.Flag)binary_reader_.ReadByte();
		result.edge_color = ReadSinglesToColor(binary_reader_); // r, g, b, a
		result.edge_size = binary_reader_.ReadSingle();
		result.usually_texture_index = CastIntRead(binary_reader_, format_.head.textureIndexSize);
		result.sphere_texture_index = CastIntRead(binary_reader_, format_.head.textureIndexSize);
		result.sphere_mode = (PMXFormat.Material.SphereMode)binary_reader_.ReadByte();
		result.common_toon = binary_reader_.ReadByte();
		byte texture_index_size = ((result.common_toon == 0)? format_.head.textureIndexSize: (byte)1);
		result.toon_texture_index = CastIntRead(binary_reader_, texture_index_size);
		result.memo = ReadString();
		result.face_vert_count = binary_reader_.ReadUInt32(); // 面頂点数 // インデックスに変換する場合は、材質0から順に加算
		return result;
	}

	private PMXFormat.BoneList ReadBoneList() {
		PMXFormat.BoneList result = new PMXFormat.BoneList();
		result.bone_count = binary_reader_.ReadUInt32();
		//Debug.Log("BoneCount:"+bone_count);
		result.bone = new PMXFormat.Bone[result.bone_count];
		for (int i = 0; i < result.bone_count; i++) {
			result.bone[i] = ReadBone();
		}
		return result;
	}

	private PMXFormat.Bone ReadBone() {
		PMXFormat.Bone result = new PMXFormat.Bone();
		result.bone_name = ReadString();
		result.bone_english_name = ReadString();
		result.bone_position = ReadSinglesToVector3(binary_reader_);
		result.parent_bone_index = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.transform_level = binary_reader_.ReadInt32();
		result.bone_flag = (PMXFormat.Bone.Flag)binary_reader_.ReadUInt16();
		
		if ((result.bone_flag & PMXFormat.Bone.Flag.Connection) == 0) {
			// 座標オフセットで指定
			result.position_offset = ReadSinglesToVector3(binary_reader_);
		} else {
			// ボーンで指定
			result.connection_index = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		}
		if ((result.bone_flag & (PMXFormat.Bone.Flag.AddRotation | PMXFormat.Bone.Flag.AddMove)) != 0) {
			result.additional_parent_index = CastIntRead(binary_reader_, format_.head.boneIndexSize);
			result.additional_rate = binary_reader_.ReadSingle();
		}
		if ((result.bone_flag & PMXFormat.Bone.Flag.FixedAxis) != 0) {
			result.axis_vector = ReadSinglesToVector3(binary_reader_);
		}
		if ((result.bone_flag & PMXFormat.Bone.Flag.LocalAxis) != 0) {
			result.x_axis_vector = ReadSinglesToVector3(binary_reader_);
			result.z_axis_vector = ReadSinglesToVector3(binary_reader_);
		}
		if((result.bone_flag & PMXFormat.Bone.Flag.ExternalParentTransform) != 0) {
			result.key_value = binary_reader_.ReadUInt32();
		}
		if((result.bone_flag & PMXFormat.Bone.Flag.IkFlag) != 0) {
			result.ik_data = ReadIkData();
		}
		return result;
	}

	private PMXFormat.IK_Data ReadIkData() {
		PMXFormat.IK_Data result = new PMXFormat.IK_Data();
		result.ik_bone_index = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.iterations = binary_reader_.ReadUInt32();
		result.limit_angle = binary_reader_.ReadSingle();
		result.ik_link_count = binary_reader_.ReadUInt32();
		result.ik_link = new PMXFormat.IK_Link[result.ik_link_count];
		for (int i = 0; i < result.ik_link_count; i++) {
			result.ik_link[i] = ReadIkLink();
		}
		return result;
	}

	private PMXFormat.IK_Link ReadIkLink() {
		PMXFormat.IK_Link result = new PMXFormat.IK_Link();
		result.target_bone_index = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.angle_limit = binary_reader_.ReadByte();
		if (result.angle_limit == 1) {
			result.lower_limit = ReadSinglesToVector3(binary_reader_);
			result.upper_limit = ReadSinglesToVector3(binary_reader_);
		}
		return result;
	}

	private PMXFormat.MorphList ReadMorphList() {
		PMXFormat.MorphList result = new PMXFormat.MorphList();
		result.morph_count = binary_reader_.ReadUInt32();
//		Debug.Log("SkinCount:"+result.morph_count);
		result.morph_data = new PMXFormat.MorphData[result.morph_count];
		for (int i = 0; i < result.morph_count; i++) {
			result.morph_data[i] = ReadMorphData();
		}
		return result;
	}

	private PMXFormat.MorphData ReadMorphData() {
		PMXFormat.MorphData result = new PMXFormat.MorphData();
		result.morph_name = ReadString();
		result.morph_english_name = ReadString();
		result.handle_panel = (PMXFormat.MorphData.Panel)binary_reader_.ReadByte();
		result.morph_type = (PMXFormat.MorphData.MorphType)binary_reader_.ReadByte();
		result.morph_offset_count = binary_reader_.ReadUInt32();
		result.morph_offset = new PMXFormat.MorphOffset[result.morph_offset_count];
		for (int i = 0; i < result.morph_offset_count; i++) {
			switch(result.morph_type) {
			case PMXFormat.MorphData.MorphType.Group:
			case PMXFormat.MorphData.MorphType.Flip:
				result.morph_offset[i] = ReadGroupMorphOffset();
				break;
			case PMXFormat.MorphData.MorphType.Vertex:
				result.morph_offset[i] = ReadVertexMorphOffset();
				break;
			case PMXFormat.MorphData.MorphType.Bone:
				result.morph_offset[i] = ReadBoneMorphOffset();
				break;
			case PMXFormat.MorphData.MorphType.Uv:
			case PMXFormat.MorphData.MorphType.Adduv1:
			case PMXFormat.MorphData.MorphType.Adduv2:
			case PMXFormat.MorphData.MorphType.Adduv3:
			case PMXFormat.MorphData.MorphType.Adduv4:
				result.morph_offset[i] = ReadUVMorphOffset();
				break;
			case PMXFormat.MorphData.MorphType.Material:
				result.morph_offset[i] = ReadMaterialMorphOffset();
				break;
			case PMXFormat.MorphData.MorphType.Impulse:
				result.morph_offset[i] = ReadImpulseMorphOffset();
				break;
			default:
				throw new System.FormatException();
			}
		}
		return result;
	}
	private PMXFormat.MorphOffset ReadGroupMorphOffset() {
		PMXFormat.GroupMorphOffset result = new PMXFormat.GroupMorphOffset();
		result.morph_index = CastIntRead(binary_reader_, format_.head.morphIndexSize);
		result.morph_rate = binary_reader_.ReadSingle();
		return result;
	}
	private PMXFormat.MorphOffset ReadVertexMorphOffset() {
		PMXFormat.VertexMorphOffset result = new PMXFormat.VertexMorphOffset();
		result.vertex_index = CastIntRead(binary_reader_, format_.head.vertexIndexSize);
		result.position_offset = ReadSinglesToVector3(binary_reader_);
		return result;
	}
	private PMXFormat.MorphOffset ReadBoneMorphOffset() {
		PMXFormat.BoneMorphOffset result = new PMXFormat.BoneMorphOffset();
		result.bone_index = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.move_value = ReadSinglesToVector3(binary_reader_);
		result.rotate_value = ReadSinglesToQuaternion(binary_reader_);
		return result;
	}
	private PMXFormat.MorphOffset ReadUVMorphOffset() {
		PMXFormat.UVMorphOffset result = new PMXFormat.UVMorphOffset();
		result.vertex_index = CastIntRead(binary_reader_, format_.head.vertexIndexSize);
		result.uv_offset = ReadSinglesToQuaternion(binary_reader_);
		return result;
	}
	private PMXFormat.MorphOffset ReadMaterialMorphOffset() {
		PMXFormat.MaterialMorphOffset result = new PMXFormat.MaterialMorphOffset();
		result.material_index = CastIntRead(binary_reader_, format_.head.materialIndexSize);
		result.offset_method = binary_reader_.ReadByte();
		result.diffuse = ReadSinglesToColor(binary_reader_);
		result.specular = ReadSinglesToColor(binary_reader_, 1);
		result.specularity = binary_reader_.ReadSingle();
		result.ambient = ReadSinglesToColor(binary_reader_, 1);
		result.edge_color = ReadSinglesToColor(binary_reader_);
		result.edge_size = binary_reader_.ReadSingle();
		result.texture_coefficient = ReadSinglesToColor(binary_reader_);
		result.sphere_texture_coefficient = ReadSinglesToColor(binary_reader_);
		result.toon_texture_coefficient = ReadSinglesToColor(binary_reader_);
		return result;
	}
	private PMXFormat.MorphOffset ReadImpulseMorphOffset() {
		PMXFormat.ImpulseMorphOffset result = new PMXFormat.ImpulseMorphOffset();
		result.rigidbody_index = CastIntRead(binary_reader_, format_.head.morphIndexSize);
		result.local_flag = binary_reader_.ReadByte();
		result.move_velocity = ReadSinglesToVector3(binary_reader_);
		result.rotation_torque = ReadSinglesToVector3(binary_reader_);
		return result;
	}

	private PMXFormat.DisplayFrameList ReadDisplayFrameList() {
		PMXFormat.DisplayFrameList result = new PMXFormat.DisplayFrameList();
		result.display_frame_count = binary_reader_.ReadUInt32();
		result.display_frame = new PMXFormat.DisplayFrame[result.display_frame_count];
		for (int i = 0; i < result.display_frame_count; i++) {
			result.display_frame[i] = ReadDisplayFrame();
		}
		return result;
	}

				
	private PMXFormat.DisplayFrame ReadDisplayFrame() {
		PMXFormat.DisplayFrame result = new PMXFormat.DisplayFrame();
		result.display_name = ReadString();
		result.display_english_name = ReadString();
		result.special_frame_flag = binary_reader_.ReadByte();
		result.display_element_count = binary_reader_.ReadUInt32();
		result.display_element = new PMXFormat.DisplayElement[result.display_element_count];
		for (int i = 0; i < result.display_element_count; i++) {
			result.display_element[i] = ReadDisplayElement();
		}
		return result;
	}
	
	private PMXFormat.DisplayElement ReadDisplayElement() {
		PMXFormat.DisplayElement result = new PMXFormat.DisplayElement();
		result.element_target = binary_reader_.ReadByte();
		byte element_target_index_size = ((result.element_target==0) ? format_.head.boneIndexSize : format_.head.morphIndexSize);
		result.element_target_index = CastIntRead(binary_reader_, element_target_index_size);
		return result;
	}
	
	private PMXFormat.RigidbodyList ReadRigidbodyList() {
		PMXFormat.RigidbodyList result = new PMXFormat.RigidbodyList();
		result.rigidbody_count = binary_reader_.ReadUInt32();
		result.rigidbody = new PMXFormat.Rigidbody[result.rigidbody_count];
		for (int i = 0; i < result.rigidbody_count; i++) {
			result.rigidbody[i] = ReadRigidbody();
		}
		return result;
	}
	
	private PMXFormat.Rigidbody ReadRigidbody() {
		PMXFormat.Rigidbody result = new PMXFormat.Rigidbody();
		result.rigidbody_name = ReadString();
		result.rigidbody_english_name = ReadString();
		result.rigidbody_rel_bone_index = CastIntRead(binary_reader_, format_.head.boneIndexSize);
		result.rigidbody_group_index = binary_reader_.ReadByte();
		result.Ignore_collision_group = binary_reader_.ReadUInt16();
		result.shape_type = binary_reader_.ReadByte();
		result.shape_size = ReadSinglesToVector3(binary_reader_);
		result.collider_position = ReadSinglesToVector3(binary_reader_);
		result.collider_rotation = ReadSinglesToVector3(binary_reader_);
		result.rigidbody_weight = binary_reader_.ReadSingle();
		result.rigidbody_pos_dim = binary_reader_.ReadSingle();
		result.rigidbody_rot_dim = binary_reader_.ReadSingle();
		result.rigidbody_recoil = binary_reader_.ReadSingle();
		result.rigidbody_friction = binary_reader_.ReadSingle();
		result.rigidbody_type = binary_reader_.ReadByte();
		return result;
	}
	
	private PMXFormat.RigidbodyJointList ReadRigidbodyJointList() {
		PMXFormat.RigidbodyJointList result = new PMXFormat.RigidbodyJointList();
		result.joint_count = binary_reader_.ReadUInt32();
		result.joint = new PMXFormat.Joint[result.joint_count];
		for (int i = 0; i < result.joint_count; i++) {
			result.joint[i] = ReadJoint();
		}
		return result;
	}
	
	private PMXFormat.Joint ReadJoint() {
		PMXFormat.Joint result = new PMXFormat.Joint();
		result.joint_name = ReadString();
		result.joint_english_name = ReadString();
		result.joint_type = binary_reader_.ReadByte();
		if(result.joint_type == 0){
			result.joint_rigidbody_a = CastIntRead(binary_reader_, format_.head.rigidbodyIndexSize);
			result.joint_rigidbody_b = CastIntRead(binary_reader_, format_.head.rigidbodyIndexSize);
			result.joint_pos = ReadSinglesToVector3(binary_reader_);
			result.joint_rot = ReadSinglesToVector3(binary_reader_);
			result.constrain_pos_lower = ReadSinglesToVector3(binary_reader_);
			result.constrain_pos_upper = ReadSinglesToVector3(binary_reader_);
			result.constrain_rot_lower = ReadSinglesToVector3(binary_reader_);
			result.constrain_rot_upper = ReadSinglesToVector3(binary_reader_);
			result.spring_pos = ReadSinglesToVector3(binary_reader_);
			result.spring_rot = ReadSinglesToVector3(binary_reader_);
		}
		return result;
	}

	private string ReadString()
	{
		string result;
		int stringLength = binary_reader_.ReadInt32();
		byte[] buf = binary_reader_.ReadBytes(stringLength);
		switch (string_code_) {
		case StringCode.Utf16le:
			result = Encoding.Unicode.GetString(buf);
			break;
		case StringCode.Utf8:
			result = Encoding.UTF8.GetString(buf);
			break;
		default:
			throw new System.InvalidOperationException();
		}
		return result;
	}

	private uint CastIntRead(BinaryReader bin, byte t)
	{
		uint result = 0;
		switch(t) {
		case 1:
			result = (uint)binary_reader_.ReadByte();
			if (byte.MaxValue == result) {
				result = uint.MaxValue;
			}
			break;
		case 2:
			result = (uint)binary_reader_.ReadUInt16();
			if (ushort.MaxValue == result) {
				result = uint.MaxValue;
			}
			break;
		case 4:
			result = binary_reader_.ReadUInt32();
			break;
		default:
			throw new System.ArgumentOutOfRangeException();
		}
		return result;
	}

	private static Vector3 ReadSinglesToVector3(BinaryReader binary_reader_)
	{
		const int count = 3;
		float[] result = new float[count];
		for (int i = 0; i < count; i++)
		{
			result[i] = binary_reader_.ReadSingle();
			if (float.IsNaN(result[i])) result[i] = 0.0f; //非数値なら回避
		}
		return new Vector3(result[0], result[1], result[2]);
	}
		
	private static Vector2 ReadSinglesToVector2(BinaryReader binary_reader_)
	{
		const int count = 2;
		float[] result = new float[count];
		for (int i = 0; i < count; i++)
		{
			result[i] = binary_reader_.ReadSingle();
			if (float.IsNaN(result[i])) result[i] = 0.0f; //非数値なら回避
		}
		return new Vector2(result[0], result[1]);
	}
	
	private static Color ReadSinglesToColor(BinaryReader binary_reader_)
	{
		const int count = 4;
		float[] result = new float[count];
		for (int i = 0; i < count; i++)
		{
			result[i] = binary_reader_.ReadSingle();
		}
		return new Color(result[0], result[1], result[2], result[3]);
	}
		
	private static Color ReadSinglesToColor(BinaryReader binary_reader_, float fix_alpha)
	{
		const int count = 3;
		float[] result = new float[count];
		for (int i = 0; i < count; i++)
		{
			result[i] = binary_reader_.ReadSingle();
		}
		return new Color(result[0], result[1], result[2], fix_alpha);
	}

	private Quaternion ReadSinglesToQuaternion(BinaryReader binary_reader_)
	{
		const int count = 4;
		float[] result = new float[count];
		for (int i = 0; i < count; i++)
		{
			result[i] = binary_reader_.ReadSingle();
			if (float.IsNaN(result[i])) result[i] = 0.0f; //非数値なら回避
		}
		return new Quaternion(result[0], result[1], result[2], result[3]);
	}
	
	private enum StringCode {
		Utf16le,
		Utf8,
	}
		
	string			file_path_;
	BinaryReader	binary_reader_;
	PMXFormat		format_;
	StringCode		string_code_;
}
