4 * Copyright 2008 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/debug.h"
29 #include "d3dxof_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3dxof_parsing
);
36 #define MAKEFOUR(a,b,c,d) ((DWORD)a + ((DWORD)b << 8) + ((DWORD)c << 16) + ((DWORD)d << 24))
37 #define XOFFILE_FORMAT_MAGIC MAKEFOUR('x','o','f',' ')
38 #define XOFFILE_FORMAT_VERSION_302 MAKEFOUR('0','3','0','2')
39 #define XOFFILE_FORMAT_VERSION_303 MAKEFOUR('0','3','0','3')
40 #define XOFFILE_FORMAT_BINARY MAKEFOUR('b','i','n',' ')
41 #define XOFFILE_FORMAT_TEXT MAKEFOUR('t','x','t',' ')
42 #define XOFFILE_FORMAT_BINARY_MSZIP MAKEFOUR('b','z','i','p')
43 #define XOFFILE_FORMAT_TEXT_MSZIP MAKEFOUR('t','z','i','p')
44 #define XOFFILE_FORMAT_COMPRESSED MAKEFOUR('c','m','p',' ')
45 #define XOFFILE_FORMAT_FLOAT_BITS_32 MAKEFOUR('0','0','3','2')
46 #define XOFFILE_FORMAT_FLOAT_BITS_64 MAKEFOUR('0','0','6','4')
48 #define TOKEN_ERROR 0xffff
51 #define TOKEN_STRING 2
52 #define TOKEN_INTEGER 3
54 #define TOKEN_INTEGER_LIST 6
55 #define TOKEN_FLOAT_LIST 7
56 #define TOKEN_OBRACE 10
57 #define TOKEN_CBRACE 11
58 #define TOKEN_OPAREN 12
59 #define TOKEN_CPAREN 13
60 #define TOKEN_OBRACKET 14
61 #define TOKEN_CBRACKET 15
62 #define TOKEN_OANGLE 16
63 #define TOKEN_CANGLE 17
65 #define TOKEN_COMMA 19
66 #define TOKEN_SEMICOLON 20
67 #define TOKEN_TEMPLATE 31
69 #define TOKEN_DWORD 41
70 #define TOKEN_FLOAT 42
71 #define TOKEN_DOUBLE 43
73 #define TOKEN_UCHAR 45
74 #define TOKEN_SWORD 46
75 #define TOKEN_SDWORD 47
77 #define TOKEN_LPSTR 49
78 #define TOKEN_UNICODE 50
79 #define TOKEN_CSTRING 51
80 #define TOKEN_ARRAY 52
82 #define CLSIDFMT "<%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X>"
84 /* FOURCC to string conversion for debug messages */
85 static const char *debugstr_fourcc(DWORD fourcc
)
87 if (!fourcc
) return "'null'";
88 return wine_dbg_sprintf ("\'%c%c%c%c\'",
89 (char)(fourcc
), (char)(fourcc
>> 8),
90 (char)(fourcc
>> 16), (char)(fourcc
>> 24));
93 static const char* get_primitive_string(DWORD token
)
127 static void dump_template(xtemplate
* templates_array
, xtemplate
* ptemplate
)
132 clsid
= &ptemplate
->class_id
;
134 wine_dbg_printf("template %s\n", ptemplate
->name
);
135 wine_dbg_printf("{\n");
136 wine_dbg_printf(CLSIDFMT
"\n", clsid
->Data1
, clsid
->Data2
, clsid
->Data3
, clsid
->Data4
[0],
137 clsid
->Data4
[1], clsid
->Data4
[2], clsid
->Data4
[3], clsid
->Data4
[4], clsid
->Data4
[5], clsid
->Data4
[6], clsid
->Data4
[7]);
138 for (j
= 0; j
< ptemplate
->nb_members
; j
++)
140 if (ptemplate
->members
[j
].nb_dims
)
141 wine_dbg_printf("array ");
142 if (ptemplate
->members
[j
].type
== TOKEN_NAME
)
143 wine_dbg_printf("%s ", templates_array
[ptemplate
->members
[j
].idx_template
].name
);
145 wine_dbg_printf("%s ", get_primitive_string(ptemplate
->members
[j
].type
));
146 wine_dbg_printf("%s", ptemplate
->members
[j
].name
);
147 for (k
= 0; k
< ptemplate
->members
[j
].nb_dims
; k
++)
149 if (ptemplate
->members
[j
].dim_fixed
[k
])
150 wine_dbg_printf("[%ld]", ptemplate
->members
[j
].dim_value
[k
]);
152 wine_dbg_printf("[%s]", ptemplate
->members
[ptemplate
->members
[j
].dim_value
[k
]].name
);
154 wine_dbg_printf(";\n");
157 wine_dbg_printf("[...]\n");
158 else if (ptemplate
->nb_children
)
160 wine_dbg_printf("[%s", ptemplate
->children
[0]);
161 for (j
= 1; j
< ptemplate
->nb_children
; j
++)
162 wine_dbg_printf(",%s", ptemplate
->children
[j
]);
163 wine_dbg_printf("]\n");
165 wine_dbg_printf("}\n");
168 static BOOL
read_bytes(parse_buffer
* buf
, LPVOID data
, DWORD size
)
170 if (buf
->rem_bytes
< size
)
172 memcpy(data
, buf
->buffer
, size
);
174 buf
->rem_bytes
-= size
;
178 static void rewind_bytes(parse_buffer
* buf
, DWORD size
)
181 buf
->rem_bytes
+= size
;
184 HRESULT
parse_header(parse_buffer
* buf
, BYTE
** decomp_buffer_ptr
)
186 /* X File common header:
187 * 0-3 -> Magic Number (format identifier)
188 * 4-7 -> Format Version
189 * 8-11 -> Format Type (text or binary, decompressed or compressed)
190 * 12-15 -> Float Size (32 or 64 bits) */
193 if (!read_bytes(buf
, header
, sizeof(header
)))
194 return DXFILEERR_BADFILETYPE
;
196 if (TRACE_ON(d3dxof_parsing
))
199 memcpy(string
, header
, 16);
201 TRACE("header = '%s'\n", string
);
204 if (header
[0] != XOFFILE_FORMAT_MAGIC
)
205 return DXFILEERR_BADFILETYPE
;
207 if (header
[1] != XOFFILE_FORMAT_VERSION_302
&& header
[1] != XOFFILE_FORMAT_VERSION_303
)
208 return DXFILEERR_BADFILEVERSION
;
210 if (header
[2] != XOFFILE_FORMAT_BINARY
&& header
[2] != XOFFILE_FORMAT_TEXT
&&
211 header
[2] != XOFFILE_FORMAT_BINARY_MSZIP
&& header
[2] != XOFFILE_FORMAT_TEXT_MSZIP
)
213 WARN("File type %s unknown\n", debugstr_fourcc(header
[2]));
214 return DXFILEERR_BADFILETYPE
;
217 if (header
[3] != XOFFILE_FORMAT_FLOAT_BITS_32
&& header
[3] != XOFFILE_FORMAT_FLOAT_BITS_64
)
218 return DXFILEERR_BADFILEFLOATSIZE
;
220 buf
->txt
= header
[2] == XOFFILE_FORMAT_TEXT
|| header
[2] == XOFFILE_FORMAT_TEXT_MSZIP
;
222 if (header
[2] == XOFFILE_FORMAT_BINARY_MSZIP
|| header
[2] == XOFFILE_FORMAT_TEXT_MSZIP
)
224 /* Extended header for compressed data:
225 * 16-19 -> size of decompressed file including xof header,
226 * 20-21 -> size of first decompressed MSZIP chunk, 22-23 -> size of first compressed MSZIP chunk
227 * 24-xx -> compressed MSZIP data chunk
228 * xx-xx -> size of next decompressed MSZIP chunk, xx-xx -> size of next compressed MSZIP chunk
229 * xx-xx -> compressed MSZIP data chunk
230 * .............................................................................................. */
232 DWORD decomp_file_size
;
233 WORD decomp_chunk_size
;
234 WORD comp_chunk_size
;
235 LPBYTE decomp_buffer
;
237 if (!read_bytes(buf
, &decomp_file_size
, sizeof(decomp_file_size
)))
238 return DXFILEERR_BADFILETYPE
;
240 TRACE("Compressed format %s detected: decompressed file size with xof header = %lu.\n",
241 debugstr_fourcc(header
[2]), decomp_file_size
);
243 /* Does not take xof header into account */
244 decomp_file_size
-= 16;
246 decomp_buffer
= HeapAlloc(GetProcessHeap(), 0, decomp_file_size
);
249 ERR("Out of memory\n");
250 return DXFILEERR_BADALLOC
;
252 *decomp_buffer_ptr
= decomp_buffer
;
254 while (buf
->rem_bytes
)
256 if (!read_bytes(buf
, &decomp_chunk_size
, sizeof(decomp_chunk_size
)))
257 return DXFILEERR_BADFILETYPE
;
258 if (!read_bytes(buf
, &comp_chunk_size
, sizeof(comp_chunk_size
)))
259 return DXFILEERR_BADFILETYPE
;
261 TRACE("Process chunk: compressed_size = %d, decompressed_size = %d\n",
262 comp_chunk_size
, decomp_chunk_size
);
264 err
= mszip_decompress(comp_chunk_size
, decomp_chunk_size
, (char*)buf
->buffer
, (char*)decomp_buffer
);
267 WARN("Error while decompressing MSZIP chunk %d\n", err
);
268 HeapFree(GetProcessHeap(), 0, decomp_buffer
);
269 return DXFILEERR_BADALLOC
;
271 buf
->rem_bytes
-= comp_chunk_size
;
272 buf
->buffer
+= comp_chunk_size
;
273 decomp_buffer
+= decomp_chunk_size
;
276 if ((decomp_buffer
- *decomp_buffer_ptr
) != decomp_file_size
)
277 ERR("Size of all decompressed chunks (%Iu) does not match decompressed file size (%lu).\n",
278 decomp_buffer
- *decomp_buffer_ptr
, decomp_file_size
);
280 /* Use decompressed data */
281 buf
->buffer
= *decomp_buffer_ptr
;
282 buf
->rem_bytes
= decomp_file_size
;
285 TRACE("Header is correct\n");
290 static void dump_TOKEN(WORD token
)
292 #define DUMP_TOKEN(t) case t: TRACE(#t "\n"); break
295 DUMP_TOKEN(TOKEN_NAME
);
296 DUMP_TOKEN(TOKEN_STRING
);
297 DUMP_TOKEN(TOKEN_INTEGER
);
298 DUMP_TOKEN(TOKEN_GUID
);
299 DUMP_TOKEN(TOKEN_INTEGER_LIST
);
300 DUMP_TOKEN(TOKEN_FLOAT_LIST
);
301 DUMP_TOKEN(TOKEN_OBRACE
);
302 DUMP_TOKEN(TOKEN_CBRACE
);
303 DUMP_TOKEN(TOKEN_OPAREN
);
304 DUMP_TOKEN(TOKEN_CPAREN
);
305 DUMP_TOKEN(TOKEN_OBRACKET
);
306 DUMP_TOKEN(TOKEN_CBRACKET
);
307 DUMP_TOKEN(TOKEN_OANGLE
);
308 DUMP_TOKEN(TOKEN_CANGLE
);
309 DUMP_TOKEN(TOKEN_DOT
);
310 DUMP_TOKEN(TOKEN_COMMA
);
311 DUMP_TOKEN(TOKEN_SEMICOLON
);
312 DUMP_TOKEN(TOKEN_TEMPLATE
);
313 DUMP_TOKEN(TOKEN_WORD
);
314 DUMP_TOKEN(TOKEN_DWORD
);
315 DUMP_TOKEN(TOKEN_FLOAT
);
316 DUMP_TOKEN(TOKEN_DOUBLE
);
317 DUMP_TOKEN(TOKEN_CHAR
);
318 DUMP_TOKEN(TOKEN_UCHAR
);
319 DUMP_TOKEN(TOKEN_SWORD
);
320 DUMP_TOKEN(TOKEN_SDWORD
);
321 DUMP_TOKEN(TOKEN_VOID
);
322 DUMP_TOKEN(TOKEN_LPSTR
);
323 DUMP_TOKEN(TOKEN_UNICODE
);
324 DUMP_TOKEN(TOKEN_CSTRING
);
325 DUMP_TOKEN(TOKEN_ARRAY
);
328 TRACE("Unknown token %d\n", token
);
334 static BOOL
is_space(char c
)
348 static BOOL
is_operator(char c
)
367 static inline BOOL
is_separator(char c
)
369 return is_space(c
) || is_operator(c
);
372 static WORD
get_operator_token(char c
)
381 return TOKEN_OBRACKET
;
383 return TOKEN_CBRACKET
;
395 return TOKEN_SEMICOLON
;
400 static BOOL
is_keyword(parse_buffer
* buf
, const char* keyword
)
402 char tmp
[8]; /* longest keyword size (template) */
403 DWORD len
= strlen(keyword
);
405 if (!read_bytes(buf
, tmp
, len
))
407 if (_strnicmp(tmp
, keyword
, len
))
409 rewind_bytes(buf
, len
);
413 if (!read_bytes(buf
, tmp
, 1))
415 if (is_separator(tmp
[0]))
417 rewind_bytes(buf
, 1);
420 rewind_bytes(buf
, len
+1);
424 static WORD
get_keyword_token(parse_buffer
* buf
)
426 if (is_keyword(buf
, "template"))
427 return TOKEN_TEMPLATE
;
428 if (is_keyword(buf
, "WORD"))
430 if (is_keyword(buf
, "DWORD"))
432 if (is_keyword(buf
, "FLOAT"))
434 if (is_keyword(buf
, "DOUBLE"))
436 if (is_keyword(buf
, "CHAR"))
438 if (is_keyword(buf
, "UCHAR"))
440 if (is_keyword(buf
, "SWORD"))
442 if (is_keyword(buf
, "SDWORD"))
444 if (is_keyword(buf
, "VOID"))
446 if (is_keyword(buf
, "STRING"))
448 if (is_keyword(buf
, "UNICODE"))
449 return TOKEN_UNICODE
;
450 if (is_keyword(buf
, "CSTRING"))
451 return TOKEN_CSTRING
;
452 if (is_keyword(buf
, "array"))
458 static BOOL
is_guid(parse_buffer
* buf
)
466 if (buf
->rem_bytes
< 38 || *buf
->buffer
!= '<')
469 while (pos
< sizeof(tmp
) - 2 && *(buf
->buffer
+pos
) != '>')
471 tmp
[pos
] = *(buf
->buffer
+pos
);
476 if (pos
!= 38 /* <+36+> */)
478 TRACE("Wrong guid %s (%lu).\n", tmp
, pos
);
482 buf
->rem_bytes
-= pos
;
484 ret
= sscanf(tmp
, "<%08lx-%04lx-%04lx-%02lx%02lx-%02lx%02lx%02lx%02lx%02lx%02lx>",
485 &class_id
.Data1
, tab
, tab
+1, tab
+2, tab
+3, tab
+4, tab
+5, tab
+6, tab
+7, tab
+8, tab
+9);
488 TRACE("Wrong guid %s (%lu).\n", tmp
, pos
);
491 TRACE("Found guid %s (%lu).\n", tmp
, pos
);
493 class_id
.Data2
= tab
[0];
494 class_id
.Data3
= tab
[1];
495 class_id
.Data4
[0] = tab
[2];
496 class_id
.Data4
[1] = tab
[3];
497 class_id
.Data4
[2] = tab
[4];
498 class_id
.Data4
[3] = tab
[5];
499 class_id
.Data4
[4] = tab
[6];
500 class_id
.Data4
[5] = tab
[7];
501 class_id
.Data4
[6] = tab
[8];
502 class_id
.Data4
[7] = tab
[9];
504 *(GUID
*)buf
->value
= class_id
;
509 static BOOL
is_name(parse_buffer
* buf
)
515 while (pos
< buf
->rem_bytes
&& !is_separator(c
= *(buf
->buffer
+pos
)))
517 if (!(((c
>= 'a') && (c
<= 'z')) || ((c
>= 'A') && (c
<= 'Z')) || ((c
>= '0') && (c
<= '9')) || (c
== '_') || (c
== '-')))
519 if (pos
< sizeof(tmp
))
523 tmp
[min(pos
, sizeof(tmp
) - 1)] = 0;
527 TRACE("Wrong name %s\n", tmp
);
532 buf
->rem_bytes
-= pos
;
534 TRACE("Found name %s\n", tmp
);
535 strcpy((char*)buf
->value
, tmp
);
540 static BOOL
is_float(parse_buffer
* buf
)
548 while (pos
< buf
->rem_bytes
&& !is_separator(c
= *(buf
->buffer
+pos
)))
550 if (!((!pos
&& (c
== '-')) || ((c
>= '0') && (c
<= '9')) || (!dot
&& (c
== '.'))))
554 if (pos
< sizeof(tmp
))
558 tmp
[min(pos
, sizeof(tmp
) - 1)] = 0;
561 buf
->rem_bytes
-= pos
;
563 sscanf(tmp
, "%f", &decimal
);
565 TRACE("Found float %s - %f\n", tmp
, decimal
);
567 *(float*)buf
->value
= decimal
;
572 static BOOL
is_integer(parse_buffer
* buf
)
579 while (pos
< buf
->rem_bytes
&& !is_separator(c
= *(buf
->buffer
+pos
)))
581 if (!((c
>= '0') && (c
<= '9')))
583 if (pos
< sizeof(tmp
))
587 tmp
[min(pos
, sizeof(tmp
) - 1)] = 0;
590 buf
->rem_bytes
-= pos
;
592 sscanf(tmp
, "%ld", &integer
);
594 TRACE("Found integer %s - %ld.\n", tmp
, integer
);
596 *(DWORD
*)buf
->value
= integer
;
601 static BOOL
is_string(parse_buffer
* buf
)
608 if (*buf
->buffer
!= '"')
611 while ((pos
+1) < buf
->rem_bytes
)
613 c
= *(buf
->buffer
+pos
+1);
619 if (pos
< sizeof(tmp
))
623 tmp
[min(pos
, sizeof(tmp
) - 1)] = 0;
627 TRACE("Wrong string %s\n", tmp
);
631 buf
->buffer
+= pos
+ 2;
632 buf
->rem_bytes
-= pos
+ 2;
634 TRACE("Found string %s\n", tmp
);
635 strcpy((char*)buf
->value
, tmp
);
640 static WORD
parse_TOKEN(parse_buffer
* buf
)
649 if (!read_bytes(buf
, &c
, 1))
651 if ((c
== '#') || (c
== '/'))
653 /* Handle comment (# or //) */
656 if (!read_bytes(buf
, &c
, 1))
664 if (!read_bytes(buf
, &c
, 1))
671 if (is_operator(c
) && (c
!= '<'))
673 token
= get_operator_token(c
);
683 rewind_bytes(buf
, 1);
685 if ((token
= get_keyword_token(buf
)))
695 token
= TOKEN_INTEGER
;
714 FIXME("Unrecognize element\n");
721 if (!buf
->list_nb_elements
)
723 if (!read_bytes(buf
, &token
, 2))
726 /* Convert integer and float list into separate elements */
727 if (token
== TOKEN_INTEGER_LIST
)
729 if (!read_bytes(buf
, &buf
->list_nb_elements
, 4))
731 token
= TOKEN_INTEGER
;
732 buf
->list_type_float
= FALSE
;
733 TRACE("Integer list (TOKEN_INTEGER_LIST) of size %lu.\n", buf
->list_nb_elements
);
735 else if (token
== TOKEN_FLOAT_LIST
)
737 if (!read_bytes(buf
, &buf
->list_nb_elements
, 4))
740 buf
->list_type_float
= TRUE
;
741 TRACE("Float list (TOKEN_FLOAT_LIST) of size %lu.\n", buf
->list_nb_elements
);
745 if (buf
->list_nb_elements
)
747 if (buf
->list_separator
)
749 buf
->list_nb_elements
--;
750 buf
->list_separator
= FALSE
;
751 /* Insert separator between each value, and since list does not accept separator at the end
752 use a comma so any extra separator will generate an error */
759 if (!read_bytes(buf
, &value
, 4))
761 *(DWORD
*)buf
->value
= value
;
763 buf
->list_separator
= TRUE
;
764 /* Convert list into a series of their basic type counterpart */
765 token
= buf
->list_type_float
? TOKEN_FLOAT
: TOKEN_INTEGER
;
776 char *name
= (char*)buf
->value
;
778 if (!read_bytes(buf
, &count
, 4))
780 if (!read_bytes(buf
, name
, count
))
783 TRACE("name = %s\n", name
);
790 if (!read_bytes(buf
, &integer
, 4))
792 TRACE("integer = %lu.\n", integer
);
794 *(DWORD
*)buf
->value
= integer
;
802 if (!read_bytes(buf
, &class_id
, 16))
804 sprintf(strguid
, CLSIDFMT
, class_id
.Data1
, class_id
.Data2
, class_id
.Data3
, class_id
.Data4
[0],
805 class_id
.Data4
[1], class_id
.Data4
[2], class_id
.Data4
[3], class_id
.Data4
[4], class_id
.Data4
[5],
806 class_id
.Data4
[6], class_id
.Data4
[7]);
807 TRACE("guid = %s\n", strguid
);
809 *(GUID
*)buf
->value
= class_id
;
815 char *string
= (char*)buf
->value
;
817 if (!read_bytes(buf
, &count
, 4))
819 if (!read_bytes(buf
, string
, count
))
822 TRACE("string = %s\n", string
);
837 case TOKEN_SEMICOLON
:
863 static WORD
get_TOKEN(parse_buffer
* buf
)
865 if (buf
->token_present
)
867 buf
->token_present
= FALSE
;
868 return buf
->current_token
;
871 buf
->current_token
= parse_TOKEN(buf
);
873 return buf
->current_token
;
876 static WORD
check_TOKEN(parse_buffer
* buf
)
878 if (buf
->token_present
)
879 return buf
->current_token
;
881 buf
->current_token
= parse_TOKEN(buf
);
882 buf
->token_present
= TRUE
;
884 return buf
->current_token
;
887 static inline BOOL
is_primitive_type(WORD token
)
912 static BOOL
parse_template_option_info(parse_buffer
* buf
)
914 xtemplate
* cur_template
= &buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
];
916 if (check_TOKEN(buf
) == TOKEN_DOT
)
919 if (get_TOKEN(buf
) != TOKEN_DOT
)
921 if (get_TOKEN(buf
) != TOKEN_DOT
)
923 cur_template
->open
= TRUE
;
929 if (get_TOKEN(buf
) != TOKEN_NAME
)
931 strcpy(cur_template
->children
[cur_template
->nb_children
], (char*)buf
->value
);
932 if (check_TOKEN(buf
) == TOKEN_GUID
)
934 cur_template
->nb_children
++;
935 if (check_TOKEN(buf
) != TOKEN_COMMA
)
939 cur_template
->open
= FALSE
;
945 static BOOL
parse_template_members_list(parse_buffer
* buf
)
954 cur_member
= &buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].members
[idx_member
];
956 if (check_TOKEN(buf
) == TOKEN_ARRAY
)
962 if (check_TOKEN(buf
) == TOKEN_NAME
)
964 cur_member
->type
= get_TOKEN(buf
);
965 if (!strcmp((char*)buf
->value
, "indexColor"))
967 /* Case sensitive legacy type indexColor is described in the first template */
968 cur_member
->idx_template
= 0;
972 cur_member
->idx_template
= 1;
973 while (cur_member
->idx_template
< buf
->pdxf
->nb_xtemplates
)
975 if (!stricmp((char*)buf
->value
, buf
->pdxf
->xtemplates
[cur_member
->idx_template
].name
))
977 cur_member
->idx_template
++;
979 if (cur_member
->idx_template
== buf
->pdxf
->nb_xtemplates
)
981 WARN("Reference to a nonexistent template '%s'\n", (char*)buf
->value
);
986 else if (is_primitive_type(check_TOKEN(buf
)))
987 cur_member
->type
= get_TOKEN(buf
);
991 if (get_TOKEN(buf
) != TOKEN_NAME
)
993 strcpy(cur_member
->name
, (char*)buf
->value
);
997 while (check_TOKEN(buf
) == TOKEN_OBRACKET
)
999 if (nb_dims
>= MAX_ARRAY_DIM
)
1001 FIXME("Too many dimensions (%d) for multi-dimensional array\n", nb_dims
+ 1);
1005 if (check_TOKEN(buf
) == TOKEN_INTEGER
)
1008 cur_member
->dim_fixed
[nb_dims
] = TRUE
;
1009 cur_member
->dim_value
[nb_dims
] = *(DWORD
*)buf
->value
;
1014 if (get_TOKEN(buf
) != TOKEN_NAME
)
1016 for (i
= 0; i
< idx_member
; i
++)
1018 if (!strcmp((char*)buf
->value
, buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].members
[i
].name
))
1020 if (buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].members
[i
].nb_dims
)
1022 ERR("Array cannot be used to specify variable array size\n");
1025 if (buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].members
[i
].type
!= TOKEN_DWORD
)
1027 FIXME("Only DWORD supported to specify variable array size\n");
1033 if (i
== idx_member
)
1035 ERR("Reference to unknown member %s\n", (char*)buf
->value
);
1038 cur_member
->dim_fixed
[nb_dims
] = FALSE
;
1039 cur_member
->dim_value
[nb_dims
] = i
;
1041 if (get_TOKEN(buf
) != TOKEN_CBRACKET
)
1047 cur_member
->nb_dims
= nb_dims
;
1049 if (get_TOKEN(buf
) != TOKEN_SEMICOLON
)
1055 buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].nb_members
= idx_member
;
1060 static BOOL
parse_template_parts(parse_buffer
* buf
)
1062 if (!parse_template_members_list(buf
))
1064 if (check_TOKEN(buf
) == TOKEN_OBRACKET
)
1067 if (!parse_template_option_info(buf
))
1069 if (get_TOKEN(buf
) != TOKEN_CBRACKET
)
1076 static BOOL
parse_template(parse_buffer
* buf
)
1078 if (get_TOKEN(buf
) != TOKEN_TEMPLATE
)
1080 if (get_TOKEN(buf
) != TOKEN_NAME
)
1082 strcpy(buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].name
, (char*)buf
->value
);
1083 if (get_TOKEN(buf
) != TOKEN_OBRACE
)
1085 if (get_TOKEN(buf
) != TOKEN_GUID
)
1087 buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].class_id
= *(GUID
*)buf
->value
;
1088 if (!parse_template_parts(buf
))
1090 if (get_TOKEN(buf
) != TOKEN_CBRACE
)
1093 TRACE("%lu - %s - %s\n", buf
->pdxf
->nb_xtemplates
, buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].name
,
1094 debugstr_guid(&buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
].class_id
));
1095 buf
->pdxf
->nb_xtemplates
++;
1100 BOOL
parse_templates(parse_buffer
* buf
, BOOL templates_only
)
1102 while (check_TOKEN(buf
) != TOKEN_NONE
)
1104 if (templates_only
&& (check_TOKEN(buf
) != TOKEN_TEMPLATE
))
1106 if (!parse_template(buf
))
1108 WARN("Template is not correct\n");
1113 TRACE("Template successfully parsed:\n");
1114 if (TRACE_ON(d3dxof_parsing
))
1115 dump_template(buf
->pdxf
->xtemplates
, &buf
->pdxf
->xtemplates
[buf
->pdxf
->nb_xtemplates
- 1]);
1121 static BOOL
check_buffer(parse_buffer
* buf
, ULONG size
)
1123 if ((buf
->cur_pos_data
+ size
) > buf
->capacity
)
1126 ULONG new_capacity
= buf
->capacity
? 2 * buf
->capacity
: 100000;
1128 pdata
= HeapAlloc(GetProcessHeap(), 0, new_capacity
);
1131 memcpy(pdata
, buf
->pdata
, buf
->cur_pos_data
);
1132 HeapFree(GetProcessHeap(), 0, buf
->pdata
);
1133 buf
->capacity
= new_capacity
;
1135 buf
->pxo
->root
->pdata
= pdata
;
1140 static BOOL
parse_object_parts(parse_buffer
* buf
, BOOL allow_optional
);
1141 static BOOL
parse_object_members_list(parse_buffer
* buf
)
1145 xtemplate
* pt
= buf
->pxt
[buf
->level
];
1147 buf
->pxo
->nb_members
= pt
->nb_members
;
1149 for (i
= 0; i
< pt
->nb_members
; i
++)
1153 BOOL basic_type
= TRUE
;
1155 buf
->pxo
->members
[i
].name
= pt
->members
[i
].name
;
1156 buf
->pxo
->members
[i
].start
= buf
->cur_pos_data
;
1158 for (k
= 0; k
< pt
->members
[i
].nb_dims
; k
++)
1160 if (pt
->members
[i
].dim_fixed
[k
])
1161 nb_elems
*= pt
->members
[i
].dim_value
[k
];
1163 nb_elems
*= *(DWORD
*)(buf
->pxo
->root
->pdata
+ buf
->pxo
->members
[pt
->members
[i
].dim_value
[k
]].start
);
1166 TRACE("Elements to consider: %lu.\n", nb_elems
);
1168 for (k
= 0; k
< nb_elems
; k
++)
1170 if (pt
->members
[i
].type
== TOKEN_NAME
)
1174 TRACE("Found sub-object %s\n", buf
->pdxf
->xtemplates
[pt
->members
[i
].idx_template
].name
);
1177 /* To do template lookup */
1178 for (j
= 0; j
< buf
->pdxf
->nb_xtemplates
; j
++)
1180 if (!stricmp(buf
->pdxf
->xtemplates
[pt
->members
[i
].idx_template
].name
, buf
->pdxf
->xtemplates
[j
].name
))
1182 buf
->pxt
[buf
->level
] = &buf
->pdxf
->xtemplates
[j
];
1186 if (j
== buf
->pdxf
->nb_xtemplates
)
1188 ERR("Unknown template %s\n", (char*)buf
->value
);
1192 TRACE("Enter %s\n", buf
->pdxf
->xtemplates
[pt
->members
[i
].idx_template
].name
);
1193 if (!parse_object_parts(buf
, FALSE
))
1202 token
= check_TOKEN(buf
);
1203 if (token
== TOKEN_INTEGER
)
1206 TRACE("%s = %ld.\n", pt
->members
[i
].name
, *(DWORD
*)buf
->value
);
1207 /* Assume larger size */
1208 if (!check_buffer(buf
, 4))
1210 if (pt
->members
[i
].type
== TOKEN_WORD
)
1212 *(WORD
*)(buf
->pdata
+ buf
->cur_pos_data
) = *(DWORD
*)buf
->value
;
1213 buf
->cur_pos_data
+= 2;
1215 else if (pt
->members
[i
].type
== TOKEN_DWORD
)
1217 *(DWORD
*)(buf
->pdata
+ buf
->cur_pos_data
) = *(DWORD
*)buf
->value
;
1218 buf
->cur_pos_data
+= 4;
1222 FIXME("Token %ld not supported.\n", pt
->members
[i
].type
);
1226 else if (token
== TOKEN_FLOAT
)
1229 TRACE("%s = %f\n", pt
->members
[i
].name
, *(float*)buf
->value
);
1230 if (!check_buffer(buf
, 4))
1232 if (pt
->members
[i
].type
== TOKEN_FLOAT
)
1234 *(float *)(buf
->pdata
+ buf
->cur_pos_data
) = *(float *)buf
->value
;
1235 buf
->cur_pos_data
+= 4;
1239 FIXME("Token %ld not supported.\n", pt
->members
[i
].type
);
1243 else if (token
== TOKEN_LPSTR
)
1246 TRACE("%s = %s\n", pt
->members
[i
].name
, (char*)buf
->value
);
1247 if (!check_buffer(buf
, sizeof(LPSTR
)))
1249 if (pt
->members
[i
].type
== TOKEN_LPSTR
)
1251 int len
= strlen((char*)buf
->value
) + 1;
1252 if ((buf
->cur_pstrings
- buf
->pstrings
+ len
) > MAX_STRINGS_BUFFER
)
1254 FIXME("Buffer too small %p %p %d\n", buf
->cur_pstrings
, buf
->pstrings
, len
);
1257 strcpy((char*)buf
->cur_pstrings
, (char*)buf
->value
);
1258 *(((LPCSTR
*)(buf
->pdata
+ buf
->cur_pos_data
))) = (char*)buf
->cur_pstrings
;
1259 buf
->cur_pstrings
+= len
;
1260 buf
->cur_pos_data
+= sizeof(LPSTR
);
1264 FIXME("Token %ld not supported.\n", pt
->members
[i
].type
);
1270 WARN("Unexpected token %ld.\n", token
);
1277 /* Handle separator only for basic types */
1278 token
= check_TOKEN(buf
);
1279 if ((token
!= TOKEN_COMMA
) && (token
!= TOKEN_SEMICOLON
))
1281 /* Allow multi-semicolons + single comma separator */
1282 while (check_TOKEN(buf
) == TOKEN_SEMICOLON
)
1284 if (check_TOKEN(buf
) == TOKEN_COMMA
)
1289 buf
->pxo
->members
[i
].size
= buf
->cur_pos_data
- buf
->pxo
->members
[i
].start
;
1295 static BOOL
parse_object_parts(parse_buffer
* buf
, BOOL allow_optional
)
1297 buf
->pxo
->nb_children
= 0;
1299 if (!parse_object_members_list(buf
))
1304 buf
->pxo
->size
= buf
->cur_pos_data
- buf
->pxo
->pos_data
;
1308 if (check_TOKEN(buf
) == TOKEN_OBRACE
)
1312 if (get_TOKEN(buf
) != TOKEN_NAME
)
1314 if (get_TOKEN(buf
) != TOKEN_CBRACE
)
1316 TRACE("Found optional reference %s\n", (char*)buf
->value
);
1317 for (i
= 0; i
< (buf
->nb_pxo_globals
+1); i
++)
1319 for (j
= 0; j
< (buf
->pxo_globals
[i
])[0].nb_subobjects
; j
++)
1321 if (!strcmp((buf
->pxo_globals
[i
])[j
].name
, (char*)buf
->value
))
1326 if (i
== (buf
->nb_pxo_globals
+1))
1328 ERR("Reference to unknown object %s\n", (char*)buf
->value
);
1332 if (buf
->pxo
->root
->nb_subobjects
>= MAX_SUBOBJECTS
)
1334 FIXME("Too many sub-objects\n");
1338 buf
->pxo
->children
[buf
->pxo
->nb_children
] = &buf
->pxo_tab
[buf
->pxo
->root
->nb_subobjects
++];
1339 buf
->pxo
->children
[buf
->pxo
->nb_children
]->ptarget
= &(buf
->pxo_globals
[i
])[j
];
1340 buf
->pxo
->children
[buf
->pxo
->nb_children
]->binary
= FALSE
;
1341 buf
->pxo
->nb_children
++;
1343 else if (check_TOKEN(buf
) == TOKEN_NAME
)
1345 xobject
* pxo
= buf
->pxo
;
1347 if (buf
->pxo
->root
->nb_subobjects
>= MAX_SUBOBJECTS
)
1349 FIXME("Too many sub-objects\n");
1353 buf
->pxo
= buf
->pxo
->children
[buf
->pxo
->nb_children
] = &buf
->pxo_tab
[buf
->pxo
->root
->nb_subobjects
];
1354 pxo
->root
->nb_subobjects
++;
1356 TRACE("Enter optional %s\n", (char*)buf
->value
);
1358 if (!parse_object(buf
))
1365 buf
->pxo
->nb_children
++;
1372 if (buf
->pxo
->nb_children
> MAX_CHILDREN
)
1374 FIXME("Too many children: %lu.\n", buf
->pxo
->nb_children
);
1381 BOOL
parse_object(parse_buffer
* buf
)
1385 buf
->pxo
->pos_data
= buf
->cur_pos_data
;
1386 buf
->pxo
->ptarget
= NULL
;
1387 buf
->pxo
->binary
= FALSE
;
1388 buf
->pxo
->root
= buf
->pxo_tab
;
1390 if (get_TOKEN(buf
) != TOKEN_NAME
)
1393 /* To do template lookup */
1394 for (i
= 0; i
< buf
->pdxf
->nb_xtemplates
; i
++)
1396 if (!stricmp((char*)buf
->value
, buf
->pdxf
->xtemplates
[i
].name
))
1398 buf
->pxt
[buf
->level
] = &buf
->pdxf
->xtemplates
[i
];
1399 memcpy(&buf
->pxo
->type
, &buf
->pdxf
->xtemplates
[i
].class_id
, 16);
1403 if (i
== buf
->pdxf
->nb_xtemplates
)
1405 ERR("Unknown template %s\n", (char*)buf
->value
);
1409 if (check_TOKEN(buf
) == TOKEN_NAME
)
1412 strcpy(buf
->pxo
->name
, (char*)buf
->value
);
1415 buf
->pxo
->name
[0] = 0;
1417 if (get_TOKEN(buf
) != TOKEN_OBRACE
)
1419 if (check_TOKEN(buf
) == TOKEN_GUID
)
1422 memcpy(&buf
->pxo
->class_id
, buf
->value
, 16);
1425 memset(&buf
->pxo
->class_id
, 0, 16);
1427 if (!parse_object_parts(buf
, TRUE
))
1429 if (get_TOKEN(buf
) != TOKEN_CBRACE
)
1432 /* For seeking to a possibly eof to avoid parsing another object next time */