37#define DSF_MAX_VERSION 1
39#define IDX_UNSET ((uint64_t)-1)
41static dsf_atom_t *parse_atom(
const uint8_t *buf,
size_t bufsz,
42 char reason[DSF_REASON_SZ], uint64_t abs_off);
44static bool_t parse_atom_list(
const uint8_t *buf, uint64_t bufsz,
45 list_t *atoms,
char reason[DSF_REASON_SZ], uint64_t abs_off);
46static bool_t parse_prop_atom(
dsf_atom_t *atom,
char reason[DSF_REASON_SZ]);
47static void destroy_prop_atom(
dsf_atom_t *atom);
48static void destroy_planar_numeric_atom(
dsf_atom_t *atom);
51 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
59 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
61 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
63 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
65 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
67 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
69 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
71 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
73 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
75 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
77 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb);
79#define DSF_CMD_ID_MAX 34
82 { DSF_POOL_SEL, pool_sel_cb },
83 { DSF_JUNCT_OFFSET_SEL, junct_off_cb },
84 { DSF_SET_DEFN8, set_defn_cb },
85 { DSF_SET_DEFN16, set_defn_cb },
86 { DSF_SET_DEFN32, set_defn_cb },
87 { DSF_ROAD_SUBTYPE, road_subt_cb },
89 { DSF_OBJ_RNG, obj_cb },
90 { DSF_NET_CHAIN, net_chain_cb },
91 { DSF_NET_CHAIN_RNG, net_chain_cb },
92 { DSF_NET_CHAIN32, net_chain_cb },
93 { DSF_POLY, poly_cb },
94 { DSF_POLY_RNG, poly_cb },
95 { DSF_NEST_POLY, poly_cb },
96 { DSF_NEST_POLY_RNG, poly_cb },
97 { DSF_TERR_PATCH, terr_patch_cb },
98 { DSF_TERR_PATCH_FLAGS, terr_patch_cb },
99 { DSF_TERR_PATCH_FLAGS_N_LOD, terr_patch_cb },
104 { DSF_PATCH_TRIA, patch_tria_cb },
105 { DSF_PATCH_TRIA_XPOOL, patch_tria_cb },
106 { DSF_PATCH_TRIA_RNG, patch_tria_cb },
107 { DSF_PATCH_TRIA_STRIP, patch_tria_cb },
108 { DSF_PATCH_TRIA_STRIP_XPOOL, patch_tria_cb },
109 { DSF_PATCH_TRIA_STRIP_RNG, patch_tria_cb },
110 { DSF_PATCH_TRIA_FAN, patch_tria_cb },
111 { DSF_PATCH_TRIA_FAN_XPOOL, patch_tria_cb },
112 { DSF_PATCH_TRIA_FAN_RNG, patch_tria_cb },
113 { DSF_COMMENT8, comment_cb },
114 { DSF_COMMENT16, comment_cb },
115 { DSF_COMMENT32, comment_cb }
119data_type2str(dsf_data_type_t data_type)
122 case DSF_DATA_SINT16:
124 case DSF_DATA_UINT16:
126 case DSF_DATA_SINT32:
128 case DSF_DATA_UINT32:
130 case DSF_DATA_SINT64:
132 case DSF_DATA_UINT64:
143static inline uint16_t
144read_u16(
const uint8_t *buf)
146#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
147 return (BSWAP16(*(uint16_t *)buf));
149 return (*(uint16_t *)buf);
153static inline uint32_t
154read_u32(
const uint8_t *buf)
156#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
157 return (BSWAP32(*(uint32_t *)buf));
159 return (*(uint32_t *)buf);
177 ssize_t bufsz =
filesz(filename);
179 FILE *fp = fopen(filename,
"rb");
180 char reason[DSF_REASON_SZ];
181 static const uint8_t magic[8] = {
182 'X',
'P',
'L',
'N',
'E',
'D',
'S',
'F'
185 if (bufsz < 12 + 16 || fp == NULL)
189 if (fread(buf, 1,
sizeof (magic), fp) !=
sizeof (magic))
191 readsz =
sizeof (magic);
193 if (memcmp(buf, magic,
sizeof (magic)) == 0) {
195 while (readsz < bufsz) {
196 size_t n = fread(&buf[readsz], 1, bufsz - readsz, fp);
201 if (!feof(fp) && readsz < bufsz) {
202 logMsg(
"Error reading DSF %s: %s", filename,
208 }
else if (
test_7z(buf,
sizeof (magic))) {
220 logMsg(
"Error parsing DSF %s: %s", filename, reason);
234parse_prop_atom(
dsf_atom_t *atom,
char reason[DSF_REASON_SZ])
236 const char *payload_end =
237 (
const char *)(atom->payload + atom->payload_sz);
239 ASSERT3U(atom->id, ==, DSF_ATOM_PROP);
243 atom->subtype_inited = B_TRUE;
245 if (atom->payload_sz < 2) {
246 snprintf(reason, DSF_REASON_SZ,
"PROP atom too short");
249 for (
const char *name = (
const char *)atom->payload;
250 name < payload_end;) {
251 size_t name_len = strnlen(name, payload_end - name);
256 if (name_len == (
size_t)(payload_end - name)) {
257 snprintf(reason, DSF_REASON_SZ,
"PROP atom contains "
258 "an unterminated name string");
261 value = name + name_len + 1;
262 if (value >= payload_end) {
263 snprintf(reason, DSF_REASON_SZ,
"Last name-value pair "
264 "in PROP atom is missing the value");
267 value_len = strnlen(value, payload_end - value);
268 if (value_len == (
size_t)(payload_end - value)) {
269 snprintf(reason, DSF_REASON_SZ,
"PROP atom contains "
270 "an unterminated value string");
278 name = value + value_len + 1;
284#define CHECK_LEN(x) \
286 if (start + (x) > end) { \
287 snprintf(reason, DSF_REASON_SZ, "planar numeric atom " \
288 "%c%c%c%c at %lx, plane %u contains too little " \
289 "data", DSF_ATOM_ID_PRINTF(atom), \
290 (unsigned long)atom->file_off, plane); \
294#define REALLOC_INCR (1 << 14)
295#define RESIZE(buf, fill, cap, itemsz, add) \
297 if (fill + add > cap) { \
298 cap += REALLOC_INCR; \
299 buf = realloc(buf, cap * (itemsz)); \
304type2datalen(dsf_data_type_t data_type)
307 case DSF_DATA_SINT16:
308 case DSF_DATA_UINT16:
310 case DSF_DATA_SINT32:
311 case DSF_DATA_UINT32:
314 case DSF_DATA_SINT64:
315 case DSF_DATA_UINT64:
324rle_decode(
dsf_atom_t *atom,
unsigned plane,
const uint8_t *start,
325 const uint8_t *end, dsf_data_type_t data_type, uint32_t num_values,
326 size_t *bytes_consumed,
char reason[DSF_REASON_SZ])
328 unsigned datalen = type2datalen(data_type);
333 for (uint32_t num = 0; num < num_values;) {
334 unsigned repeat, cnt;
341 RESIZE(out, num, out_cap, datalen, cnt);
345 for (
unsigned k = 0; k < cnt; k++) {
346 memcpy(&out[num * datalen], &start[i], datalen);
351 CHECK_LEN(cnt * datalen);
352 for (
unsigned k = 0; k < cnt; k++) {
353 memcpy(&out[num * datalen], &start[i], datalen);
360 if (bytes_consumed != NULL)
369diff_decode(
dsf_atom_t *atom,
unsigned plane,
const uint8_t *start,
370 const uint8_t *end, dsf_data_type_t data_type, uint32_t num_values,
371 size_t *bytes_consumed,
char reason[DSF_REASON_SZ])
373 unsigned datalen = type2datalen(data_type);
376 CHECK_LEN(num_values * datalen);
380#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
381#error "TODO: implement big-endian"
384#define DIFF_DEC(ctype) \
387 ctype *out_type = out; \
388 for (uint32_t i = 0; i < num_values; i++) { \
389 ctype val = ((ctype *)start)[i]; \
391 out_type[i] = prev; \
395 case DSF_DATA_SINT16:
398 case DSF_DATA_UINT16:
401 case DSF_DATA_SINT32:
404 case DSF_DATA_UINT32:
407 case DSF_DATA_SINT64:
410 case DSF_DATA_UINT64:
424 if (bytes_consumed != NULL)
425 *bytes_consumed = num_values * datalen;
432raw_decode(
dsf_atom_t *atom,
unsigned plane,
const uint8_t *start,
433 const uint8_t *end, dsf_data_type_t data_type, uint32_t num_values,
434 size_t *bytes_consumed,
char reason[DSF_REASON_SZ])
436 unsigned datalen = type2datalen(data_type);
439 CHECK_LEN(num_values * datalen);
442#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
443#error "TODO: implement big-endian"
445 memcpy(out, start, datalen * num_values);
448 if (bytes_consumed != NULL)
449 *bytes_consumed = num_values * datalen;
456parse_plane(
dsf_atom_t *atom,
unsigned plane, dsf_data_type_t data_type,
457 const uint8_t *start,
const uint8_t *end,
char reason[DSF_REASON_SZ])
461 uint32_t datacnt = atom->planar_atom.data_count;
462 unsigned datalen = type2datalen(data_type);
469 snprintf(reason, DSF_REASON_SZ,
"invalid encoding type %u for "
470 "planar numeric atom %c%c%c%c at %lx", enc,
471 DSF_ATOM_ID_PRINTF(atom), (
unsigned long)atom->file_off);
480 out = raw_decode(atom, plane, start, end, data_type, datacnt,
484 out = diff_decode(atom, plane, start, end, data_type,
485 datacnt, &consumed, reason);
487 case DSF_ENC_DIFF | DSF_ENC_RLE: {
488 void *tmp = rle_decode(atom, plane, start, end, data_type,
489 datacnt, &consumed, reason);
492 out = diff_decode(atom, plane, tmp, tmp + datacnt * datalen,
493 data_type, datacnt, NULL, reason);
500 tmp = rle_decode(atom, plane, start, end, data_type, datacnt,
504 out = raw_decode(atom, plane, start, end, data_type, datacnt,
514 atom->planar_atom.data[plane] = out;
516 return (consumed + 1);
526parse_planar_numeric_atom(
dsf_atom_t *atom, dsf_data_type_t data_type,
527 char reason[DSF_REASON_SZ])
530 const uint8_t *plane_p = &atom->payload[5];
531 const uint8_t *end = atom->payload + atom->payload_sz;
533 if (atom->payload_sz < 5) {
534 snprintf(reason, DSF_REASON_SZ,
"invalid planar numeric atom "
535 "%c%c%c%c at %lx: not enough payload",
536 DSF_ATOM_ID_PRINTF(atom), (
unsigned long)atom->file_off);
540 pa->data_type = data_type;
541 pa->data_count = read_u32(atom->payload);
542 pa->plane_count = atom->payload[4];
543 pa->data =
safe_calloc(pa->plane_count, sizeof (*pa->data));
544 atom->subtype_inited = B_TRUE;
546 for (
unsigned i = 0; i < pa->plane_count; i++) {
547 ssize_t len = parse_plane(atom, i, data_type,
548 plane_p, end, reason);
550 printf(
"plane parse error\n");
556 if (plane_p != end) {
557 snprintf(reason, DSF_REASON_SZ,
"planar numeric atom %c%c%c%c "
558 "at %lx contained trailing garbage",
559 DSF_ATOM_ID_PRINTF(atom), (
unsigned long)atom->file_off);
567parse_demi_atom(
dsf_atom_t *atom,
char reason[DSF_REASON_SZ])
569 const uint8_t *payload = atom->payload;
571 if (atom->payload_sz != 20) {
572 snprintf(reason, DSF_REASON_SZ,
"Invalid payload size of "
573 "DEMI atom (%x, wanted 20)", atom->payload_sz);
576 atom->demi_atom.version = *payload++;
577 if (atom->demi_atom.version != 1) {
578 snprintf(reason, DSF_REASON_SZ,
"Unsupported DEMI atom "
579 "version %d", atom->demi_atom.version);
582 atom->demi_atom.bpp = *payload++;
583 atom->demi_atom.flags = read_u16(payload);
585 atom->demi_atom.width = read_u32(payload);
587 atom->demi_atom.height = read_u32(payload);
589 atom->demi_atom.scale = *(
float *)payload;
591 atom->demi_atom.offset = *(
float *)payload;
593 atom->subtype_inited = B_TRUE;
601 ASSERT(atom->subtype_inited);
602 for (
unsigned i = 0; i < atom->planar_atom.plane_count; i++)
603 free(atom->planar_atom.data[i]);
604 free(atom->planar_atom.data);
605 atom->planar_atom.data = NULL;
613 ASSERT3U(atom->id, ==, DSF_ATOM_PROP);
614 ASSERT(atom->subtype_inited);
622parse_atom(
const uint8_t *buf,
size_t bufsz,
char reason[DSF_REASON_SZ],
633#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
634 atom->id = BSWAP32(read_u32(buf));
636 atom->id = read_u32(buf);
638 atom->payload_sz = read_u32(&buf[4]) - 8;
639 atom->payload = &buf[8];
640 if (atom->payload_sz + 8 > bufsz) {
641 snprintf(reason, DSF_REASON_SZ,
"invalid atom at %lx, "
642 "size (%lx) is too large",
643 (
unsigned long)abs_off, (
unsigned long)atom->payload_sz);
646 atom->file_off = abs_off;
648 if (atom->id == DSF_ATOM_HEAD || atom->id == DSF_ATOM_DEFN ||
649 atom->id == DSF_ATOM_GEOD || atom->id == DSF_ATOM_DEMS) {
650 if (!parse_atom_list(atom->payload, atom->payload_sz,
651 &atom->subatoms, reason, abs_off + 8))
653 }
else if (atom->id == DSF_ATOM_PROP) {
654 if (!parse_prop_atom(atom, reason))
656 }
else if (atom->id == DSF_ATOM_POOL) {
657 if (!parse_planar_numeric_atom(atom, DSF_DATA_UINT16, reason))
659 }
else if (atom->id == DSF_ATOM_PO32) {
660 if (!parse_planar_numeric_atom(atom, DSF_DATA_UINT32, reason))
662 }
else if (atom->id == DSF_ATOM_DEMI) {
663 if (!parse_demi_atom(atom, reason))
674parse_atom_list(
const uint8_t *buf, uint64_t bufsz,
list_t *atoms,
675 char reason[DSF_REASON_SZ], uint64_t abs_off)
679 for (
const uint8_t *atom_buf = buf; atom_buf < buf + bufsz;) {
681 (buf + bufsz) - atom_buf, reason,
682 abs_off + (atom_buf - buf));
687 atom_buf += atom->payload_sz + 8;
707dsf_parse(uint8_t *buf,
size_t bufsz,
char reason[DSF_REASON_SZ])
710 static const uint8_t magic[8] = {
711 'X',
'P',
'L',
'N',
'E',
'D',
'S',
'F'
719 if (bufsz < 12 + 16) {
720 snprintf(reason, DSF_REASON_SZ,
721 "file is too short (%d) to be a valid DSF", (
int)bufsz);
724 if (memcmp(buf, magic,
sizeof (magic)) != 0) {
725 snprintf(reason, DSF_REASON_SZ,
726 "file premable missing DSF magic number");
729 dsf->version = read_u32(&buf[8]);
730 if (dsf->version > DSF_MAX_VERSION) {
731 snprintf(reason, DSF_REASON_SZ,
732 "file version (%d) exceeds our max supported version (%d)",
733 dsf->version, DSF_MAX_VERSION);
736 memcpy(dsf->md5sum, &buf[bufsz - 16], 16);
737 if (!parse_atom_list(&buf[12], bufsz - (12 + 16), &dsf->atoms, reason,
760 if (atom->subtype_inited) {
763 destroy_prop_atom(atom);
767 destroy_planar_numeric_atom(atom);
775 atom->subtype_inited = B_FALSE;
798dump_prop_atom(
const dsf_atom_t *atom,
char **str,
size_t *len,
int depth)
800 char *indent =
safe_calloc((depth * INDENT_DEPTH) + 1,
803 VERIFY3U(atom->id, ==, DSF_ATOM_PROP);
805 memset(indent,
' ', depth * INDENT_DEPTH);
806 indent[depth * INDENT_DEPTH] =
'\0';
809 prop =
list_next(&atom->prop_atom.props, prop)) {
811 indent, prop->name, prop->value);
817dump_planar_atom(
const dsf_atom_t *atom,
char **str,
size_t *len,
int depth)
819 char *indent =
safe_calloc((depth * INDENT_DEPTH) + 1,
822 memset(indent,
' ', depth * INDENT_DEPTH);
823 indent[depth * INDENT_DEPTH] =
'\0';
827 "%snum planes: %d\n",
828 indent, data_type2str(atom->planar_atom.data_type),
829 indent, atom->planar_atom.data_count,
830 indent, atom->planar_atom.plane_count);
835dump_demi_atom(
const dsf_atom_t *atom,
char **str,
size_t *len,
int depth)
837 char *indent =
safe_calloc((depth * INDENT_DEPTH) + 1,
839 const char *data_type;
841 memset(indent,
' ', depth * INDENT_DEPTH);
842 indent[depth * INDENT_DEPTH] =
'\0';
844 switch (atom->demi_atom.flags & DEMI_DATA_MASK) {
855 data_type =
"<unknown>";
869 indent, atom->demi_atom.version,
870 indent, atom->demi_atom.bpp,
872 indent, (atom->demi_atom.flags >> 2) & 1,
873 indent, atom->demi_atom.flags,
874 indent, atom->demi_atom.width,
875 indent, atom->demi_atom.height,
876 indent, atom->demi_atom.scale,
877 indent, atom->demi_atom.offset);
882dump_atom(
const dsf_atom_t *atom,
char **str,
size_t *len,
int depth)
884 char *indent =
safe_calloc((depth * INDENT_DEPTH) + 1,
887 memset(indent,
' ', depth * INDENT_DEPTH);
888 indent[depth * INDENT_DEPTH] =
'\0';
893 (atom->id & 0xff000000) >> 24,
894 (atom->id & 0xff0000) >> 16,
895 (atom->id & 0xff00) >> 8,
897 (
unsigned long)atom->payload_sz);
899 if (atom->id == DSF_ATOM_PROP)
900 dump_prop_atom(atom, str, len, depth + 1);
901 else if (atom->id == DSF_ATOM_POOL)
902 dump_planar_atom(atom, str, len, depth + 1);
903 else if (atom->id == DSF_ATOM_PO32)
904 dump_planar_atom(atom, str, len, depth + 1);
905 else if (atom->id == DSF_ATOM_DEMI)
906 dump_demi_atom(atom, str, len, depth + 1);
909 subatom =
list_next(&atom->subatoms, subatom)) {
910 dump_atom(subatom, str, len, depth + 1);
930 "MD5: %02x%02x%02x%02x%02x%02x%02x%02x"
931 "%02x%02x%02x%02x%02x%02x%02x%02x\n"
933 dsf->version, (
unsigned long)dsf->size,
934 dsf->md5sum[0], dsf->md5sum[1], dsf->md5sum[2], dsf->md5sum[3],
935 dsf->md5sum[4], dsf->md5sum[5], dsf->md5sum[6], dsf->md5sum[7],
936 dsf->md5sum[8], dsf->md5sum[9], dsf->md5sum[10], dsf->md5sum[11],
937 dsf->md5sum[12], dsf->md5sum[13], dsf->md5sum[14], dsf->md5sum[15]);
940 dump_atom(atom, &str, &len, 1);
966 unsigned num_args = 0;
972 while ((atom_id = va_arg(ap, uint32_t)) != 0) {
973 (void) va_arg(ap,
unsigned);
978 lookup =
safe_calloc(num_args + 1,
sizeof (*lookup));
981 for (
unsigned i = 0; i < num_args; i++) {
982 lookup[i].atom_id = va_arg(ap, uint32_t);
983 lookup[i].idx = va_arg(ap,
unsigned);
1011 for (
int i = 0; lookup[i].atom_id != 0; i++) {
1017 if (atom->id == l->atom_id) {
1026 list = &atom->subatoms;
1054 for (
const dsf_atom_t *atom = (prev != NULL ?
1056 list_head(&parent->subatoms)); atom != NULL;
1057 atom =
list_next(&parent->subatoms, atom)) {
1058 if (atom->id == atom_id)
1082 void *userinfo,
char reason[DSF_REASON_SZ])
1086 const uint8_t *payload, *payload_end;
1087 char subreason[DSF_REASON_SZ] = { 0 };
1089 memset(&parser, 0,
sizeof (parser));
1092 parser.junct_off = IDX_UNSET;
1093 parser.defn_idx = IDX_UNSET;
1094 parser.road_subt = IDX_UNSET;
1095 parser.userinfo = userinfo;
1096 parser.reason = subreason;
1098 cmds_atom =
dsf_lookup(dsf, DSF_ATOM_CMDS, 0);
1099 if (cmds_atom == NULL) {
1101 snprintf(reason, DSF_REASON_SZ,
"CMDS atom not found");
1105 payload = cmds_atom->payload;
1106 payload_end = cmds_atom->payload + cmds_atom->payload_sz;
1107 while (payload < payload_end) {
1108 int cmd_id = *payload;
1112 parser.cmd_file_off = (payload - cmds_atom->payload) +
1113 cmds_atom->file_off + 8;
1115 ASSERT(cmd_id <= DSF_CMD_ID_MAX &&
1116 cmd_parser_info[cmd_id].cb != NULL);
1118 if (cmd_id > DSF_CMD_ID_MAX ||
1119 cmd_parser_info[cmd_id].cb == NULL) {
1120 if (reason != NULL) {
1121 snprintf(reason, DSF_REASON_SZ,
1122 "invalid command ID %x at offset %lx",
1123 cmd_id, (
long)(payload -
1124 cmds_atom->payload + cmds_atom->file_off));
1128 cmd = cmd_parser_info[cmd_id].cmd;
1129 n = cmd_parser_info[cmd_id].cb(&parser, cmd, payload + 1,
1130 payload_end - payload - 1, user_cbs[cmd]);
1132 if (reason != NULL) {
1133 snprintf(reason, DSF_REASON_SZ,
1134 "malformed command %s at offset %lx: %s",
1136 (
long)parser.cmd_file_off, subreason);
1141 ASSERT3P(payload, <=, payload_end);
1158 return (
"POOL_SEL");
1159 case DSF_JUNCT_OFFSET_SEL:
1160 return (
"JUNCT_OFFSET_SEL");
1162 return (
"SET_DEFN8");
1163 case DSF_SET_DEFN16:
1164 return (
"SET_DEFN16");
1165 case DSF_SET_DEFN32:
1166 return (
"SET_DEFN32");
1167 case DSF_ROAD_SUBTYPE:
1168 return (
"ROAD_SUBTYPE");
1174 return (
"NET_CHAIN");
1175 case DSF_NET_CHAIN_RNG:
1176 return (
"NET_CHAIN_RNG");
1177 case DSF_NET_CHAIN32:
1178 return (
"NET_CHAIN32");
1182 return (
"POLY_RNG");
1184 return (
"NEST_POLY");
1185 case DSF_NEST_POLY_RNG:
1186 return (
"NEST_POLY_RNG");
1187 case DSF_TERR_PATCH:
1188 return (
"TERR_PATCH");
1189 case DSF_TERR_PATCH_FLAGS:
1190 return (
"TERR_PATCH_FLAGS");
1191 case DSF_TERR_PATCH_FLAGS_N_LOD:
1192 return (
"TERR_PATCH_FLAGS_N_LOD");
1193 case DSF_PATCH_TRIA:
1194 return (
"PATCH_TRIA");
1195 case DSF_PATCH_TRIA_XPOOL:
1196 return (
"PATCH_TRIA_XPOOL");
1197 case DSF_PATCH_TRIA_RNG:
1198 return (
"PATCH_TRIA_RNG");
1199 case DSF_PATCH_TRIA_STRIP:
1200 return (
"PATCH_TRIA_STRIP");
1201 case DSF_PATCH_TRIA_STRIP_XPOOL:
1202 return (
"PATCH_TRIA_STRIP_XPOOL");
1203 case DSF_PATCH_TRIA_STRIP_RNG:
1204 return (
"PATCH_TRIA_STRIP_RNG");
1205 case DSF_PATCH_TRIA_FAN:
1206 return (
"PATCH_TRIA_FAN");
1207 case DSF_PATCH_TRIA_FAN_XPOOL:
1208 return (
"PATCH_TRIA_FAN_XPOOL");
1209 case DSF_PATCH_TRIA_FAN_RNG:
1210 return (
"PATCH_TRIA_FAN_RNG");
1212 return (
"COMMENT8");
1214 return (
"COMMENT16");
1216 return (
"COMMENT32");
1222#define CHECK_LEN(b) \
1224 if ((b) > (int)len) { \
1225 snprintf(parser->reason, DSF_REASON_SZ, \
1226 "not enough data in command (wanted %d bytes, " \
1227 "have %d bytes)", (b), (int)len); \
1234 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1236 if (parser->pool == NULL) {
1237 snprintf(parser->reason, DSF_REASON_SZ,
1238 "no current POOL/SCAL selected");
1245 if (arg.first >= parser->pool->planar_atom.data_count) {
1246 snprintf(parser->reason, DSF_REASON_SZ,
1247 "range start index (%x) out of bounds for "
1248 "corresponding POOL atom (max: %x)", arg.first,
1249 parser->pool->planar_atom.data_count);
1252 if (arg.last_plus_one > parser->pool->planar_atom.data_count) {
1253 snprintf(parser->reason, DSF_REASON_SZ,
1254 "range end index (%x) out of bounds for "
1255 "corresponding POOL atom (max: %x)",
1257 parser->pool->planar_atom.data_count);
1260 if (arg.first >= arg.last_plus_one) {
1261 snprintf(parser->reason, DSF_REASON_SZ,
"range start "
1262 "index (%x) not lower than end index (%x)",
1263 arg.first, arg.last_plus_one);
1266 cb(cmd, &arg, parser);
1273 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1277 if (parser->pool == NULL) {
1278 snprintf(parser->reason, DSF_REASON_SZ,
1279 "no current POOL/SCAL selected");
1284 arg.num_coords = *data;
1285 CHECK_LEN(1 + arg.num_coords * 2);
1287 for (
int i = 0; i < arg.num_coords; i++) {
1288 arg.indices[i] = read_u16(&data[1 + i * 2]);
1289 if (arg.indices[i] >=
1290 parser->pool->planar_atom.data_count) {
1291 snprintf(parser->reason, DSF_REASON_SZ,
1292 "index %d (%x) out of bounds of "
1293 "corresponding POOL atom", i,
1298 cb(cmd, &arg, parser);
1300 return (1 + arg.num_coords * 2);
1305 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1309 if (parser->pool == NULL) {
1310 snprintf(parser->reason, DSF_REASON_SZ,
1311 "no current POOL/SCAL selected");
1316 arg.num_coords = *data;
1317 CHECK_LEN(1 + 2 * arg.num_coords * 2);
1319 for (
int i = 0; i < arg.num_coords; i++) {
1320 int seq = read_u16(&data[1 + i * 4]);
1321 arg.indices[i].pool =
dsf_lookup(parser->dsf,
1322 DSF_ATOM_GEOD, 0, DSF_ATOM_POOL, seq, 0);
1323 arg.indices[i].scal =
dsf_lookup(parser->dsf,
1324 DSF_ATOM_GEOD, 0, DSF_ATOM_SCAL, seq, 0);
1325 if (arg.indices[i].pool == NULL ||
1326 arg.indices[i].scal == NULL) {
1327 snprintf(parser->reason, DSF_REASON_SZ,
1328 "index %d POOL or SCAL atom %d not found",
1332 arg.indices[i].idx = read_u16(&data[1 + i * 4 + 2]);
1333 if (arg.indices[i].idx >=
1334 arg.indices[i].pool->planar_atom.data_count) {
1335 snprintf(parser->reason, DSF_REASON_SZ,
1336 "index %d (%x) out of bounds of "
1337 "corresponding POOL atom", i,
1338 arg.indices[i].idx);
1342 cb(cmd, &arg, parser);
1344 return (1 + 2 * arg.num_coords * 2);
1349 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1354 pool_idx = read_u16(data);
1356 parser->pool =
dsf_lookup(parser->dsf, DSF_ATOM_GEOD, 0,
1357 DSF_ATOM_POOL, pool_idx, 0);
1358 parser->scal =
dsf_lookup(parser->dsf, DSF_ATOM_GEOD, 0,
1359 DSF_ATOM_SCAL, pool_idx, 0);
1360 if (parser->pool == NULL || parser->scal == NULL) {
1361 snprintf(parser->reason, DSF_REASON_SZ,
1362 "POOL or SCAL atom with index %d not found", pool_idx);
1367 cb(cmd, NULL, parser);
1374 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1377 parser->junct_off = read_u32(data);
1379 cb(cmd, NULL, parser);
1385 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1388 if (cmd == DSF_SET_DEFN8) {
1390 parser->defn_idx = *data;
1392 }
else if (cmd == DSF_SET_DEFN16) {
1394 parser->defn_idx = read_u16(data);
1399 parser->defn_idx = read_u32(data);
1403 cb(cmd, NULL, parser);
1409 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1412 parser->road_subt = *data;
1414 cb(cmd, NULL, parser);
1420 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1422 if (cmd == DSF_OBJ) {
1425 idx = read_u16(data);
1427 cb(cmd, (
void *)(uintptr_t)idx, parser);
1431 return (parse_idx_rng_common(parser, cmd, data, len, cb));
1437 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1439 if (cmd == DSF_NET_CHAIN) {
1440 return (parse_idx_list_common(parser, cmd, data, len, cb));
1441 }
else if (cmd == DSF_NET_CHAIN_RNG) {
1442 return (parse_idx_rng_common(parser, cmd, data, len, cb));
1446 ASSERT3U(cmd, ==, DSF_NET_CHAIN32);
1448 arg.num_coords = *data;
1449 CHECK_LEN(1 + arg.num_coords * 4);
1451 for (
int i = 0; i < arg.num_coords; i++)
1452 arg.indices[i] = read_u32(&data[1 + i * 4]);
1453 cb(cmd, &arg, parser);
1455 return (1 + arg.num_coords * 4);
1464 arg->num_coords = *data;
1468 CHECK_LEN(arg->num_coords * 2);
1470 return (1 + arg->num_coords * 2);
1472 for (
int i = 0; i < arg->num_coords; i++) {
1473 arg->indices[i] = read_u16(&data[i * 2]);
1474 if (arg->indices[i] >= parser->pool->planar_atom.data_count) {
1475 snprintf(parser->reason, DSF_REASON_SZ,
1476 "index %d (%x) out of bounds of corresponding "
1477 "POOL atom", i, arg->indices[i]);
1481 cb(DSF_NEST_POLY, &arg, parser);
1483 return (1 + arg->num_coords * 2);
1487 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1489 if (cmd == DSF_POLY || cmd == DSF_NEST_POLY_RNG) {
1493 arg.param = read_u16(data);
1494 arg.num_coords = data[2];
1495 if (cmd == DSF_NEST_POLY_RNG)
1498 CHECK_LEN(3 + arg.num_coords * 2);
1500 for (
int i = 0; i < arg.num_coords; i++)
1501 arg.indices[i] = read_u16(3 + &data[i * 2]);
1502 cb(cmd, &arg, parser);
1504 return (3 + arg.num_coords * 2);
1505 }
else if (cmd == DSF_POLY_RNG) {
1513 cb(cmd, &arg, parser);
1523 arg.param = read_u16(data);
1528 for (
int i = 0; i < n_wind; i++) {
1529 int l = parse_nest_poly_wind(parser, data, len, cb,
1541 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1543 if (cmd == DSF_TERR_PATCH) {
1545 cb(cmd, NULL, parser);
1547 }
else if (cmd == DSF_TERR_PATCH_FLAGS) {
1550 cb(cmd, (
void *)(uintptr_t)*data, parser);
1553 ASSERT3U(cmd, ==, DSF_TERR_PATCH_FLAGS_N_LOD);
1557 *data, *(
float *)(data + 1), *(
float *)(data + 5)
1559 cb(cmd, &arg, parser);
1567 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1569 if (cmd == DSF_PATCH_TRIA) {
1570 return (parse_idx_list_common(parser, cmd, data, len, cb));
1571 }
else if (cmd == DSF_PATCH_TRIA_XPOOL) {
1572 return (parse_idx_list_xpool_common(parser, cmd, data, len,
1574 }
else if (cmd == DSF_PATCH_TRIA_RNG) {
1575 return (parse_idx_rng_common(parser, cmd, data, len, cb));
1576 }
else if (cmd == DSF_PATCH_TRIA_STRIP) {
1577 return (parse_idx_list_common(parser, cmd, data, len, cb));
1578 }
else if (cmd == DSF_PATCH_TRIA_STRIP_XPOOL) {
1579 return (parse_idx_list_xpool_common(parser, cmd, data, len,
1581 }
else if (cmd == DSF_PATCH_TRIA_STRIP_RNG) {
1582 return (parse_idx_rng_common(parser, cmd, data, len, cb));
1583 }
else if (cmd == DSF_PATCH_TRIA_FAN) {
1584 return (parse_idx_list_common(parser, cmd, data, len, cb));
1585 }
else if (cmd == DSF_PATCH_TRIA_FAN_XPOOL) {
1586 return (parse_idx_list_xpool_common(parser, cmd, data, len,
1589 ASSERT3U(cmd, ==, DSF_PATCH_TRIA_FAN_RNG);
1590 return (parse_idx_rng_common(parser, cmd, data, len, cb));
1596 const uint8_t *data,
size_t len, dsf_cmd_cb_t cb)
1601 if (cmd == DSF_COMMENT8) {
1605 }
else if (cmd == DSF_COMMENT16) {
1608 arg.len = read_u16(data);
1609 }
else if (cmd == DSF_COMMENT32) {
1612 arg.len = read_u32(data);
1615 arg.data = &data[1];
1616 cb(cmd, &arg, parser);
1619 return (hdrlen + arg.len);
#define ASSERT3P(x, op, y)
#define ASSERT3U(x, op, y)
#define VERIFY3U(x, op, y)
void * decompress_7z(const char *filename, size_t *out_len)
bool_t test_7z(const void *in_buf, size_t len)
const dsf_atom_t * dsf_iter(const dsf_atom_t *parent, uint32_t atom_id, const dsf_atom_t *prev)
const dsf_atom_t * dsf_lookup_v(const dsf_t *dsf, const dsf_lookup_t *lookup)
bool_t dsf_parse_cmds(const dsf_t *dsf, dsf_cmd_cb_t user_cbs[NUM_DSF_CMDS], void *userinfo, char reason[DSF_REASON_SZ])
dsf_t * dsf_parse(uint8_t *buf, size_t bufsz, char reason[DSF_REASON_SZ])
const dsf_atom_t * dsf_lookup(const dsf_t *dsf,...)
const char * dsf_cmd2str(dsf_cmd_t cmd)
dsf_t * dsf_init(const char *filename)
void dsf_fini(dsf_t *dsf)
char * dsf_dump(const dsf_t *dsf)
ssize_t filesz(const char *filename)
void append_format(char **str, size_t *sz, const char *format,...)
void list_destroy(list_t *)
void * list_head(const list_t *)
void list_create(list_t *, size_t, size_t)
void * list_next(const list_t *, const void *)
void * list_remove_head(list_t *)
void list_insert_tail(list_t *, void *)
static void * safe_calloc(size_t nmemb, size_t size)
static void * safe_malloc(size_t size)