OSDN Git Service

add pmx_test
[meshio/pymeshio.git] / pymeshio / pmx.py
1 #!/usr/bin/env python\r
2 # coding: utf-8\r
3 """\r
4 pmx file io library.\r
5 \r
6 pmx file format:\r
7     PMDEditor's Lib/PMX仕様/PMX仕様.txt\r
8 """\r
9 __author__="ousttrue"\r
10 __license__="zlib"\r
11 __versioon__="0.0.1"\r
12 \r
13 \r
14 import io\r
15 import os\r
16 import struct\r
17 \r
18 \r
19 class Model(object):\r
20     """pmx data holder\r
21 \r
22     version: pmx version\r
23     """\r
24     __slots__=[\r
25             'version', # pmx version\r
26             'name', # model name\r
27             'english_name', # model name in english\r
28             'comment', # model comment\r
29             'english_comment', # model comment in english\r
30             ]\r
31     def __init__(self):\r
32         self.version=0.0\r
33 \r
34 \r
35 class IO(object):\r
36     """pmx loader\r
37 \r
38     Attributes:\r
39         name: model name\r
40     """\r
41     def __init__(self):\r
42         self.__io=None\r
43         self.__pos=-1\r
44         self.__end=-1\r
45         self.__model=Model()\r
46 \r
47     def read(self, path: 'filepath') -> Model:\r
48         size=os.path.getsize(path)\r
49         with open(path, "rb") as f:\r
50             if self.load(path, f, size):\r
51                 return self.__model\r
52 \r
53     def load(self, path: 'filepath', io: io.IOBase, size: int) -> bool: \r
54         self.__io=io\r
55         self.__end=size\r
56         self.__check_position()\r
57 \r
58         if not self.__loadHeader():\r
59             return False\r
60         self.__check_position()\r
61         # model info\r
62         self.__model.name = self.__read_text()\r
63         self.__model.english_name = self.__read_text()\r
64         self.__model.comment = self.__read_text()\r
65         self.__model.english_comment = self.__read_text()\r
66         return True\r
67 \r
68     def __str__(self) -> str:\r
69         return '<PmxIO>'\r
70 \r
71     def __check_position(self):\r
72         self.__pos=self.__io.tell()\r
73 \r
74     def __unpack(self, fmt: str, size: int) -> "read value as format":\r
75         return struct.unpack(fmt, self.__io.read(size))[0]\r
76 \r
77     def __loadHeader(self) -> bool:\r
78         signature=self.__unpack("4s", 4)\r
79         if signature!=b"PMX ":\r
80             print("invalid signature", signature)\r
81             return False\r
82         version=self.__unpack("f", 4)\r
83         if version!=2.0:\r
84             print("unknown version", version)\r
85         self.__model.version=version\r
86         # flags\r
87         flag_bytes=self.__unpack("B", 1)\r
88         if flag_bytes!=8:\r
89             print("invalid flag length", flag_bytes)\r
90             return False\r
91         # text encoding\r
92         text_encoding=self.__unpack("B", 1)\r
93         if text_encoding==0:\r
94             def read_text():\r
95                 size=self.__unpack("I", 4)\r
96                 return self.__unpack("{0}s".format(size), size).decode("UTF16")\r
97         elif text_encoding==1:\r
98             def read_text():\r
99                 size=self.__unpack("I", 4)\r
100                 return self.__unpack("{0}s".format(size), size).decode("UTF8")\r
101         else:\r
102             print("unknown text encoding", text_encoding)\r
103             return False\r
104         self.__read_text=read_text\r
105         self.__unpack("B", 1)\r
106         self.__unpack("B", 1)\r
107         self.__unpack("B", 1)\r
108         self.__unpack("B", 1)\r
109         self.__unpack("B", 1)\r
110         self.__unpack("B", 1)\r
111         self.__unpack("B", 1)\r
112         return True\r
113 \r