00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "file/file.h"
00021 #include "util/bits.h"
00022 #include "util/logging.h"
00023 #include "util/macro.h"
00024 #include "mobj_parse.h"
00025
00026 #include <stdlib.h>
00027
00028 #define MOBJ_SIG1 ('M' << 24 | 'O' << 16 | 'B' << 8 | 'J')
00029 #define MOBJ_SIG2A ('0' << 24 | '2' << 16 | '0' << 8 | '0')
00030 #define MOBJ_SIG2B ('0' << 24 | '1' << 16 | '0' << 8 | '0')
00031
00032 static int _mobj_parse_header(BITSTREAM *bs, int *extension_data_start)
00033 {
00034 uint32_t sig1, sig2;
00035
00036 bs_seek_byte(bs, 0);
00037
00038 sig1 = bs_read(bs, 32);
00039 sig2 = bs_read(bs, 32);
00040
00041 if (sig1 != MOBJ_SIG1 ||
00042 (sig2 != MOBJ_SIG2A &&
00043 sig2 != MOBJ_SIG2B)) {
00044 BD_DEBUG(DBG_NAV, "MovieObject.bdmv failed signature match: expected MOBJ0100 got %8.8s\n", bs->buf);
00045 return 0;
00046 }
00047
00048 *extension_data_start = bs_read(bs, 32);
00049
00050 return 1;
00051 }
00052
00053 void mobj_parse_cmd(uint8_t *buf, MOBJ_CMD *cmd)
00054 {
00055 BITBUFFER bb;
00056 bb_init(&bb, buf, 12);
00057
00058 cmd->insn.op_cnt = bb_read(&bb, 3);
00059 cmd->insn.grp = bb_read(&bb, 2);
00060 cmd->insn.sub_grp = bb_read(&bb, 3);
00061
00062 cmd->insn.imm_op1 = bb_read(&bb, 1);
00063 cmd->insn.imm_op2 = bb_read(&bb, 1);
00064 bb_skip(&bb, 2);
00065 cmd->insn.branch_opt = bb_read(&bb, 4);
00066
00067 bb_skip(&bb, 4);
00068 cmd->insn.cmp_opt = bb_read(&bb, 4);
00069
00070 bb_skip(&bb, 3);
00071 cmd->insn.set_opt = bb_read(&bb, 5);
00072
00073 cmd->dst = bb_read(&bb, 32);
00074 cmd->src = bb_read(&bb, 32);
00075 }
00076
00077 static int _mobj_parse_object(BITSTREAM *bs, MOBJ_OBJECT *obj)
00078 {
00079 int i;
00080
00081 obj->resume_intention_flag = bs_read(bs, 1);
00082 obj->menu_call_mask = bs_read(bs, 1);
00083 obj->title_search_mask = bs_read(bs, 1);
00084
00085 bs_skip(bs, 13);
00086
00087 obj->num_cmds = bs_read(bs, 16);
00088 obj->cmds = calloc(obj->num_cmds, sizeof(MOBJ_CMD));
00089
00090 for (i = 0; i < obj->num_cmds; i++) {
00091 uint8_t buf[12];
00092 bs_read_bytes(bs, buf, 12);
00093 mobj_parse_cmd(buf, &obj->cmds[i]);
00094 }
00095
00096 return 1;
00097 }
00098
00099 void mobj_free(MOBJ_OBJECTS **p)
00100 {
00101 if (p && *p) {
00102
00103 int i;
00104 for (i = 0 ; i < (*p)->num_objects; i++) {
00105 X_FREE((*p)->objects[i].cmds);
00106 }
00107
00108 X_FREE(*p);
00109 }
00110 }
00111
00112 MOBJ_OBJECTS *mobj_parse(const char *file_name)
00113 {
00114 BITSTREAM bs;
00115 BD_FILE_H *fp;
00116 MOBJ_OBJECTS *objects = NULL;
00117 uint16_t num_objects;
00118 uint32_t data_len;
00119 int extension_data_start, i;
00120
00121 fp = file_open(file_name, "rb");
00122 if (!fp) {
00123 BD_DEBUG(DBG_NAV | DBG_CRIT, "error opening %s\n", file_name);
00124 return NULL;
00125 }
00126
00127 bs_init(&bs, fp);
00128
00129 if (!_mobj_parse_header(&bs, &extension_data_start)) {
00130 BD_DEBUG(DBG_NAV | DBG_CRIT, "%s: invalid header\n", file_name);
00131 goto error;
00132 }
00133
00134 bs_seek_byte(&bs, 40);
00135
00136 data_len = bs_read(&bs, 32);
00137 bs_skip(&bs, 32);
00138 num_objects = bs_read(&bs, 16);
00139
00140 objects = calloc(1, sizeof(MOBJ_OBJECTS) + num_objects * sizeof(MOBJ_OBJECT));
00141 objects->num_objects = num_objects;
00142
00143 for (i = 0; i < objects->num_objects; i++) {
00144 if (!_mobj_parse_object(&bs, &objects->objects[i])) {
00145 BD_DEBUG(DBG_NAV | DBG_CRIT, "%s: error parsing object %d\n", file_name, i);
00146 goto error;
00147 }
00148 }
00149
00150 file_close(fp);
00151
00152 return objects;
00153
00154 error:
00155 mobj_free(&objects);
00156 file_close(fp);
00157 return NULL;
00158 }