Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
July 2018
- 74 participants
- 637 discussions
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/comctl32/trackbar.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/dlls/comctl32/trackbar.c b/dlls/comctl32/trackbar.c
index d774823d60..e717528fd4 100644
--- a/dlls/comctl32/trackbar.c
+++ b/dlls/comctl32/trackbar.c
@@ -1474,6 +1474,7 @@ TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
{
RECT rect;
int clientWidth, clientMetric;
+ HDC hdc;
/* initial thumb length */
clientMetric = (infoPtr->dwStyle & TBS_ENABLESELRANGE) ? 23 : 21;
@@ -1488,6 +1489,10 @@ TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
else
infoPtr->uThumbLen = clientWidth > 9 ? clientWidth - 6 : 4;
+ hdc = GetDC(infoPtr->hwndSelf);
+ infoPtr->uThumbLen = MulDiv(infoPtr->uThumbLen, GetDeviceCaps(hdc, LOGPIXELSX), 96);
+ ReleaseDC(infoPtr->hwndSelf, hdc);
+
TRACKBAR_CalcChannel (infoPtr);
TRACKBAR_UpdateThumb (infoPtr);
infoPtr->flags &= ~TB_SELECTIONCHANGED;
--
2.18.0
2
1
This patch adds the ability to decompress DXTn textures, and is meant to
be used for DXTn 3D textures because they are not supported properly in
drivers.
Signed-off-by: Connor McAdams <conmanx360(a)gmail.com>
---
dlls/wined3d/texture.c | 54 +++++++-
dlls/wined3d/utils.c | 271 ++++++++++++++++++++++++++++++++++++-----
dlls/wined3d/wined3d_private.h | 4 +
3 files changed, 294 insertions(+), 35 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index c316906..5959048 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -567,6 +567,8 @@ static void wined3d_texture_allocate_gl_mutable_storage(struct wined3d_texture *
unsigned int level, level_count, layer, layer_count;
GLsizei width, height, depth;
GLenum target;
+ GLint gl_format;
+ GLint gl_type;
level_count = texture->level_count;
if (texture->target == GL_TEXTURE_1D_ARRAY || texture->target == GL_TEXTURE_2D_ARRAY)
@@ -578,6 +580,18 @@ static void wined3d_texture_allocate_gl_mutable_storage(struct wined3d_texture *
{
target = wined3d_texture_get_sub_resource_target(texture, layer * level_count);
+ if (texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS)
+ {
+ gl_internal_format = GL_RGBA8;
+ gl_format = GL_BGRA;
+ gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+ else
+ {
+ gl_format = format->glFormat;
+ gl_type = format->glType;
+ }
+
for (level = 0; level < level_count; ++level)
{
width = wined3d_texture_get_level_pow2_width(texture, level);
@@ -596,19 +610,19 @@ static void wined3d_texture_allocate_gl_mutable_storage(struct wined3d_texture *
depth = wined3d_texture_get_level_depth(texture, level);
GL_EXTCALL(glTexImage3D(target, level, gl_internal_format, width, height,
target == GL_TEXTURE_2D_ARRAY ? texture->layer_count : depth, 0,
- format->glFormat, format->glType, NULL));
+ gl_format, gl_type, NULL));
checkGLcall("glTexImage3D");
}
else if (target == GL_TEXTURE_1D)
{
gl_info->gl_ops.gl.p_glTexImage1D(target, level, gl_internal_format,
- width, 0, format->glFormat, format->glType, NULL);
+ width, 0, gl_format, gl_type, NULL);
}
else
{
gl_info->gl_ops.gl.p_glTexImage2D(target, level, gl_internal_format, width,
target == GL_TEXTURE_1D_ARRAY ? texture->layer_count : height, 0,
- format->glFormat, format->glType, NULL);
+ gl_format, gl_type, NULL);
checkGLcall("glTexImage2D");
}
}
@@ -624,6 +638,9 @@ static void wined3d_texture_allocate_gl_immutable_storage(struct wined3d_texture
GLsizei height = wined3d_texture_get_level_pow2_height(texture, 0);
GLsizei width = wined3d_texture_get_level_pow2_width(texture, 0);
+ if (texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS)
+ gl_internal_format = GL_RGBA8;
+
switch (texture->target)
{
case GL_TEXTURE_3D:
@@ -1948,6 +1965,37 @@ void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int s
bo.addr += src_box->left * format->byte_count;
}
+ if (texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS)
+ {
+ unsigned int dst_row_pitch, dst_slice_pitch;
+ void *src_mem;
+ void (*decompress)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch,
+ unsigned int dst_row_pitch, unsigned int dst_slice_pitch,
+ unsigned int width, unsigned int height, unsigned int depth);
+
+ decompress = format->decompress;
+ format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, WINED3DUSAGE_TEXTURE);
+
+ wined3d_format_calculate_pitch(format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
+
+ if (!(converted_mem = heap_calloc(update_d, dst_slice_pitch)))
+ {
+ ERR("Failed to allocate upload buffer.\n");
+ return;
+ }
+ src_mem = context_map_bo_address(context, &bo, src_slice_pitch,
+ GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
+ decompress(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
+ dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d);
+ context_unmap_bo_address(context, &bo, GL_PIXEL_UNPACK_BUFFER);
+
+ bo.buffer_object = 0;
+ bo.addr = converted_mem;
+ src_row_pitch = dst_row_pitch;
+ src_slice_pitch = dst_slice_pitch;
+ texture->resource.format_flags &= ~WINED3DFMT_FLAG_BLOCKS;
+ }
+
if (format->upload)
{
unsigned int dst_row_pitch, dst_slice_pitch;
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 937c1bc..e6b0061 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -437,6 +437,9 @@ struct wined3d_format_texture_info
void (*download)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch,
unsigned int dst_row_pitch, unsigned int dst_slice_pitch,
unsigned int width, unsigned int height, unsigned int depth);
+ void (*decompress)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch,
+ unsigned int dst_row_pitch, unsigned int dst_slice_pitch,
+ unsigned int width, unsigned int height, unsigned int depth);
};
static void convert_l4a4_unorm(const BYTE *src, BYTE *dst, UINT src_row_pitch, UINT src_slice_pitch,
@@ -840,6 +843,206 @@ static void convert_s8_uint_d24_float(const BYTE *src, BYTE *dst, UINT src_row_p
}
}
+static void dxtn_decompress_block(const BYTE *src, BYTE *dst, UINT width, UINT height, UINT depth,
+ UINT x_pos, UINT y_pos, UINT z_pos, UINT dst_slice_pitch, UINT64 cur_block, UINT fmt, BYTE block_offset)
+{
+ UINT64 alpha_block, alpha_index, color_block, color_index;
+ const UINT64 *source;
+ DWORD *dest;
+ DWORD alpha_lookup;
+ DWORD bgra;
+ DWORD temp;
+ DWORD i, x, y;
+ WORD color[2];
+ BYTE alpha_val, color_val;
+ BYTE alpha[8];
+ BYTE r[4];
+ BYTE g[4];
+ BYTE b[4];
+
+ source = (const UINT64 *)(src + cur_block * block_offset);
+ if (fmt == WINED3DFMT_DXT1)
+ {
+ color_block = source[0];
+ alpha_block = 0;
+ }
+ else
+ {
+ alpha_block = source[0];
+ color_block = source[1];
+ }
+
+ color[0] = color_block & 0xffff;
+ color[1] = (color_block >> 16) & 0xffff;
+ for (i = 0; i < 2; ++i)
+ {
+ temp = (color[i] >> 11) * 255 + 16;
+ r[i] = (temp / 32 + temp) / 32;
+ temp = ((color[i] >> 5) & 0x3f) * 255 + 32;
+ g[i] = (temp / 64 + temp) / 64;
+ temp = (color[i] & 0x1f) * 255 + 16;
+ b[i] = (temp / 32 + temp) / 32;
+ }
+
+ if (fmt == WINED3DFMT_DXT3 || fmt == WINED3DFMT_DXT5 || color[0] > color[1])
+ {
+ for (i = 0; i < 2; ++i)
+ {
+ r[2 + i] = (2 * r[0 + i] + r[1 - i]) / 3;
+ g[2 + i] = (2 * g[0 + i] + g[1 - i]) / 3;
+ b[2 + i] = (2 * b[0 + i] + b[1 - i]) / 3;
+ }
+ }
+ else if (fmt == WINED3DFMT_DXT1 && color[0] <= color[1])
+ {
+ r[2] = (r[0] + r[1]) / 2;
+ g[2] = (g[0] + g[1]) / 2;
+ b[2] = (b[0] + b[1]) / 2;
+
+ r[3] = 0;
+ g[3] = 0;
+ b[3] = 0;
+ }
+
+ switch (fmt)
+ {
+ case WINED3DFMT_DXT1:
+ alpha_index = 0;
+ for (i = 0; i < ARRAY_SIZE(alpha); ++i)
+ alpha[i] = 255;
+ if (color[0] <= color[1])
+ alpha[3] = 0;
+ break;
+ case WINED3DFMT_DXT3:
+ alpha_index = alpha_block;
+ for (i = 0; i < ARRAY_SIZE(alpha); ++i)
+ alpha[i] = 0;
+ break;
+ case WINED3DFMT_DXT5:
+ alpha_index = (alpha_block >> 16);
+ alpha[0] = alpha_block & 0xff;
+ alpha[1] = (alpha_block >> 8) & 0xff;
+ if (alpha[0] > alpha[1])
+ {
+ for (i = 0; i < 6; ++i)
+ alpha[2 + i] = (((6 - i) * alpha[0]) + ((1 + i) * alpha[1])) / 7;
+ }
+ else if (alpha[0] <= alpha[1])
+ {
+ for (i = 0; i < 4; ++i)
+ alpha[2 + i] = (((4 - i) * alpha[0]) + ((1 + i) * alpha[1])) / 5;
+ alpha[6] = 0;
+ alpha[7] = 255;
+ }
+ break;
+ default:
+ alpha_index = 0;
+ break;
+ }
+
+ color_index = (color_block >> 32) & 0xffffffff;
+ dest = (DWORD *)(dst + z_pos * dst_slice_pitch);
+ for (y = 0; y < 4; ++y)
+ {
+ if (y_pos + y >= height)
+ break;
+ for (x = 0; x < 4; ++x)
+ {
+ if (x_pos + x >= width)
+ break;
+
+ color_val = 0;
+ alpha_val = 0;
+ bgra = 0;
+
+ color_val = (color_index >> (y * 8));
+ color_val = (color_val >> (x * 2)) & 0x3;
+ switch (fmt)
+ {
+ case WINED3DFMT_DXT1:
+ alpha_val = color_val;
+ break;
+ case WINED3DFMT_DXT3:
+ alpha_lookup = (alpha_index >> (y * 16)) & 0xffff;
+ alpha_val = (alpha_lookup >> (x * 4)) & 0xf;
+ temp = alpha_val * 255 + 8;
+ alpha[0] = (temp / 16 + temp) / 16;
+ alpha_val = 0;
+ break;
+ case WINED3DFMT_DXT5:
+ alpha_lookup = (alpha_index >> (y * 12)) & 0xfff;
+ alpha_val = (alpha_lookup >> (x * 3)) & 0x7;
+ break;
+ }
+ bgra = ((alpha[alpha_val] << 24) | (r[color_val] << 16) | (g[color_val] << 8) | b[color_val]);
+ dest[(y_pos + y) * width + (x_pos + x)] = bgra;
+ }
+ }
+}
+
+static void convert_dxt5_b8g8r8a8_unorm(const BYTE *src, BYTE *dst, UINT src_row_pitch, UINT src_slice_pitch,
+ UINT dst_row_pitch, UINT dst_slice_pitch, UINT width, UINT height, UINT depth)
+{
+ UINT64 current_block;
+ DWORD x, y, z;
+
+ current_block = 0;
+
+ for (z = 0; z < depth; ++z)
+ {
+ for (y = 0; y < height; y += 4)
+ {
+ for (x = 0; x < width; x += 4)
+ {
+ dxtn_decompress_block(src, dst, width, height, depth, x, y, z, dst_slice_pitch, current_block, WINED3DFMT_DXT5, 16);
+ current_block++;
+ }
+ }
+ }
+}
+
+static void convert_dxt3_b8g8r8a8_unorm(const BYTE *src, BYTE *dst, UINT src_row_pitch, UINT src_slice_pitch,
+ UINT dst_row_pitch, UINT dst_slice_pitch, UINT width, UINT height, UINT depth)
+{
+ UINT64 current_block;
+ DWORD x, y, z;
+
+ current_block = 0;
+
+ for (z = 0; z < depth; ++z)
+ {
+ for (y = 0; y < height; y += 4)
+ {
+ for (x = 0; x < width; x += 4)
+ {
+ dxtn_decompress_block(src, dst, width, height, depth, x, y, z, dst_slice_pitch, current_block, WINED3DFMT_DXT3, 16);
+ current_block++;
+ }
+ }
+ }
+}
+
+static void convert_dxt1_b8g8r8a8_unorm(const BYTE *src, BYTE *dst, UINT src_row_pitch, UINT src_slice_pitch,
+ UINT dst_row_pitch, UINT dst_slice_pitch, UINT width, UINT height, UINT depth)
+{
+ UINT64 current_block;
+ DWORD x, y, z;
+
+ current_block = 0;
+
+ for (z = 0; z < depth; ++z)
+ {
+ for (y = 0; y < height; y += 4)
+ {
+ for (x = 0; x < width; x += 4)
+ {
+ dxtn_decompress_block(src, dst, width, height, depth, x, y, z, dst_slice_pitch, current_block, WINED3DFMT_DXT1, 8);
+ current_block++;
+ }
+ }
+ }
+}
+
static void x8_d24_unorm_upload(const BYTE *src, BYTE *dst,
unsigned int src_row_pitch, unsigned int src_slice_pitch,
unsigned int dst_row_pitch, unsigned int dst_slice_pitch,
@@ -1066,7 +1269,7 @@ static const struct wined3d_format_texture_info format_texture_info[] =
/* format id gl_internal gl_srgb_internal gl_rt_internal
gl_format gl_type conv_byte_count
flags
- extension upload download */
+ extension upload download decompress */
/* FourCC formats */
/* GL_APPLE_ycbcr_422 claims that its '2YUV' format, which is supported via the UNSIGNED_SHORT_8_8_REV_APPLE type
* is equivalent to 'UYVY' format on Windows, and the 'YUVS' via UNSIGNED_SHORT_8_8_APPLE equates to 'YUY2'. The
@@ -1118,42 +1321,42 @@ static const struct wined3d_format_texture_info format_texture_info[] =
GL_RGBA, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
| WINED3DFMT_FLAG_SRGB_READ | WINED3DFMT_FLAG_COMPRESSED,
- EXT_TEXTURE_COMPRESSION_S3TC, NULL},
+ EXT_TEXTURE_COMPRESSION_S3TC, NULL, NULL, convert_dxt1_b8g8r8a8_unorm},
{WINED3DFMT_DXT2, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
| WINED3DFMT_FLAG_SRGB_READ | WINED3DFMT_FLAG_COMPRESSED,
- EXT_TEXTURE_COMPRESSION_S3TC, NULL},
+ EXT_TEXTURE_COMPRESSION_S3TC, NULL, NULL, convert_dxt3_b8g8r8a8_unorm},
{WINED3DFMT_DXT3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
| WINED3DFMT_FLAG_SRGB_READ | WINED3DFMT_FLAG_COMPRESSED,
- EXT_TEXTURE_COMPRESSION_S3TC, NULL},
+ EXT_TEXTURE_COMPRESSION_S3TC, NULL, NULL, convert_dxt3_b8g8r8a8_unorm},
{WINED3DFMT_DXT4, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
| WINED3DFMT_FLAG_SRGB_READ | WINED3DFMT_FLAG_COMPRESSED,
- EXT_TEXTURE_COMPRESSION_S3TC, NULL},
+ EXT_TEXTURE_COMPRESSION_S3TC, NULL, NULL, convert_dxt5_b8g8r8a8_unorm},
{WINED3DFMT_DXT5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
| WINED3DFMT_FLAG_SRGB_READ | WINED3DFMT_FLAG_COMPRESSED,
- EXT_TEXTURE_COMPRESSION_S3TC, NULL},
+ EXT_TEXTURE_COMPRESSION_S3TC, NULL, NULL, convert_dxt5_b8g8r8a8_unorm},
{WINED3DFMT_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
| WINED3DFMT_FLAG_COMPRESSED,
- EXT_TEXTURE_COMPRESSION_S3TC, NULL},
+ EXT_TEXTURE_COMPRESSION_S3TC, NULL, NULL, convert_dxt1_b8g8r8a8_unorm},
{WINED3DFMT_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
| WINED3DFMT_FLAG_COMPRESSED,
- EXT_TEXTURE_COMPRESSION_S3TC, NULL},
+ EXT_TEXTURE_COMPRESSION_S3TC, NULL, NULL, convert_dxt3_b8g8r8a8_unorm},
{WINED3DFMT_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
| WINED3DFMT_FLAG_COMPRESSED,
- EXT_TEXTURE_COMPRESSION_S3TC, NULL},
+ EXT_TEXTURE_COMPRESSION_S3TC, NULL, NULL, convert_dxt5_b8g8r8a8_unorm},
{WINED3DFMT_BC4_UNORM, GL_COMPRESSED_RED_RGTC1, GL_COMPRESSED_RED_RGTC1, 0,
GL_RED, GL_UNSIGNED_BYTE, 0,
WINED3DFMT_FLAG_TEXTURE | WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING
@@ -2928,6 +3131,7 @@ static BOOL init_format_texture_info(struct wined3d_adapter *adapter, struct win
format->conv_byte_count = format_texture_info[i].conv_byte_count;
format->upload = format_texture_info[i].upload;
format->download = format_texture_info[i].download;
+ format->decompress = format_texture_info[i].decompress;
srgb_format = NULL;
for (j = 0; j < ARRAY_SIZE(format_srgb_info); ++j)
@@ -3394,29 +3598,7 @@ static void apply_format_fixups(struct wined3d_adapter *adapter, struct wined3d_
* for dx9 GPUs support it, some do not, so not supporting DXTn volumes is OK for d3d9.
*
* Note that GL_NV_texture_compression_vtc adds this functionality to OpenGL, but the
- * block layout is not compatible with the one used by d3d. See volume_dxt5_test. */
- idx = get_format_idx(WINED3DFMT_DXT1);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_DXT2);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_DXT3);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_DXT4);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_DXT5);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_BC1_UNORM);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_BC1_UNORM_SRGB);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_BC2_UNORM);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_BC2_UNORM_SRGB);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_BC3_UNORM);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
- idx = get_format_idx(WINED3DFMT_BC3_UNORM_SRGB);
- gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
+ * block layout is not compatible with the one used by d3d. See volume_dxtn_test. */
/* Similarly with ATI1N / ATI2N and GL_ARB_texture_compression_rgtc. */
idx = get_format_idx(WINED3DFMT_ATI1N);
gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
@@ -3430,6 +3612,31 @@ static void apply_format_fixups(struct wined3d_adapter *adapter, struct wined3d_
gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
idx = get_format_idx(WINED3DFMT_BC5_SNORM);
gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE;
+
+ /* This sets up which 3D textures can be decompressed through software. */
+ idx = get_format_idx(WINED3DFMT_DXT1);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_DXT2);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_DXT3);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_DXT4);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_DXT5);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_BC1_UNORM);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_BC1_UNORM_SRGB);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_BC2_UNORM);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_BC2_UNORM_SRGB);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_BC3_UNORM);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+ idx = get_format_idx(WINED3DFMT_BC3_UNORM_SRGB);
+ gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS;
+
}
static unsigned int calculate_vertex_attribute_size(GLenum type, unsigned int component_count)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 9aa7081..b1d8b24 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -4247,6 +4247,7 @@ extern enum wined3d_format_id pixelformat_for_depth(DWORD depth) DECLSPEC_HIDDEN
#define WINED3DFMT_FLAG_BLOCKS_NO_VERIFY 0x00100000
#define WINED3DFMT_FLAG_INTEGER 0x00200000
#define WINED3DFMT_FLAG_GEN_MIPMAP 0x00400000
+#define WINED3DFMT_FLAG_DECOMPRESS 0x00800000
struct wined3d_rational
{
@@ -4306,6 +4307,9 @@ struct wined3d_format
void (*download)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch,
unsigned int dst_row_pitch, unsigned dst_slice_pitch,
unsigned int width, unsigned int height, unsigned int depth);
+ void (*decompress)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch,
+ unsigned int dst_row_pitch, unsigned dst_slice_pitch,
+ unsigned int width, unsigned int height, unsigned int depth);
enum wined3d_format_id typeless_id;
GLenum gl_view_class;
--
2.7.4
2
2
16 Jul '18
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=31829
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/segment.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c
index dc460690f6..9a9872bd4c 100644
--- a/dlls/dmime/segment.c
+++ b/dlls/dmime/segment.c
@@ -790,10 +790,16 @@ static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *st
if (!stream)
return E_POINTER;
- if (stream_get_chunk(stream, &riff) != S_OK || riff.id != FOURCC_RIFF)
+ if (stream_get_chunk(stream, &riff) != S_OK ||
+ (riff.id != FOURCC_RIFF && riff.id != mmioFOURCC('M','T','h','d')))
return DMUS_E_UNSUPPORTED_STREAM;
-
stream_reset_chunk_start(stream, &riff);
+
+ if (riff.id == mmioFOURCC('M','T','h','d')) {
+ FIXME("MIDI file loading not supported\n");
+ return S_OK;
+ }
+
hr = IDirectMusicObject_ParseDescriptor(&This->dmobj.IDirectMusicObject_iface, stream,
&This->dmobj.desc);
if (FAILED(hr))
--
2.14.4
1
0
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43642
Signed-off-by: Austin English <austinenglish(a)gmail.com>
---
dlls/ntoskrnl.exe/ntoskrnl.c | 11 +++++++++++
dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index a061241925..80e9b9e517 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -3547,7 +3547,18 @@ BOOLEAN WINAPI SeSinglePrivilegeCheck(LUID privilege, KPROCESSOR_MODE mode)
return TRUE;
}
+/*********************************************************************
+ * KeFlushQueuedDpcs (NTOSKRNL.@)
+ */
void WINAPI KeFlushQueuedDpcs(void)
{
FIXME("stub!\n");
}
+
+/*********************************************************************
+ * IoReleaseRemoveLockAndWaitEx (NTOSKRNL.@)
+ */
+void WINAPI IoReleaseRemoveLockAndWaitEx(PIO_REMOVE_LOCK lock, PVOID tag, ULONG size)
+{
+ FIXME("stub: %p %p %u\n", lock, tag, size);
+}
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 907fba8d99..662445a78c 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -436,7 +436,7 @@
@ stdcall IoRegisterPlugPlayNotification(long long ptr ptr ptr ptr ptr)
@ stdcall IoRegisterShutdownNotification(ptr)
@ stdcall IoReleaseCancelSpinLock(long)
-@ stub IoReleaseRemoveLockAndWaitEx
+@ stdcall IoReleaseRemoveLockAndWaitEx(ptr ptr long)
@ stub IoReleaseRemoveLockEx
@ stub IoReleaseVpbSpinLock
@ stub IoRemoveShareAccess
--
2.16.4
1
0
[PATCH] dbghelp: Fix loading of Mach-O load commands for 64-bit binaries.
by Ken Thomases 16 Jul '18
by Ken Thomases 16 Jul '18
16 Jul '18
Signed-off-by: Ken Thomases <ken(a)codeweavers.com>
---
dlls/dbghelp/image_private.h | 1 +
dlls/dbghelp/macho_module.c | 5 +++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/dbghelp/image_private.h b/dlls/dbghelp/image_private.h
index 9990850..a29794e 100644
--- a/dlls/dbghelp/image_private.h
+++ b/dlls/dbghelp/image_private.h
@@ -89,6 +89,7 @@ struct image_file_map
#ifdef HAVE_MACH_O_LOADER_H
struct mach_header mach_header;
+ size_t header_size; /* size of real header in file */
const struct load_command* load_commands;
const struct uuid_command* uuid;
diff --git a/dlls/dbghelp/macho_module.c b/dlls/dbghelp/macho_module.c
index 9401dfb..05130b7 100644
--- a/dlls/dbghelp/macho_module.c
+++ b/dlls/dbghelp/macho_module.c
@@ -415,7 +415,7 @@ static const struct load_command* macho_map_load_commands(struct macho_file_map*
if (fmap->load_commands == IMAGE_NO_MAP)
{
fmap->load_commands = (const struct load_command*) macho_map_range(
- fmap, sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds, NULL);
+ fmap, fmap->header_size, fmap->mach_header.sizeofcmds, NULL);
TRACE("Mapped load commands: %p\n", fmap->load_commands);
}
@@ -433,7 +433,7 @@ static void macho_unmap_load_commands(struct macho_file_map* fmap)
{
TRACE("Unmapping load commands: %p\n", fmap->load_commands);
macho_unmap_range(NULL, (const void**)&fmap->load_commands, fmap,
- sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds);
+ fmap->header_size, fmap->mach_header.sizeofcmds);
}
}
@@ -666,6 +666,7 @@ static BOOL macho_map_file(struct process *pcs, const WCHAR *filenameW,
ifm->modtype = DMT_MACHO;
ifm->addr_size = (pcs->is_64bit) ? 64 : 32;
+ fmap->header_size = (pcs->is_64bit) ? sizeof(struct mach_header_64) : sizeof(struct mach_header);
len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL);
if (!(filename = HeapAlloc(GetProcessHeap(), 0, len)))
--
2.10.2
1
0
16 Jul '18
Signed-off-by: Alex Henrie <alexhenrie24(a)gmail.com>
---
v2: Reset diff_count3 to 0 after use
dlls/ddraw/tests/d3d.c | 77 ++++++++++++++++++++++++++++++++++++--------------
1 file changed, 56 insertions(+), 21 deletions(-)
diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c
index 77836fd627..3cc40e24c4 100644
--- a/dlls/ddraw/tests/d3d.c
+++ b/dlls/ddraw/tests/d3d.c
@@ -24,6 +24,7 @@
#include "wine/test.h"
#include <limits.h>
+#include <math.h>
#include "initguid.h"
#include "ddraw.h"
#include "d3d.h"
@@ -1418,7 +1419,7 @@ static void DeviceLoadTest(void)
RECT loadrect;
POINT loadpoint;
int i, i1, i2;
- unsigned diff_count = 0, diff_count2 = 0;
+ unsigned diff_count = 0, diff_count2 = 0, diff_count3 = 0;
unsigned x, y;
BOOL load_mip_subset_broken = FALSE;
IDirectDrawPalette *palettes[5];
@@ -1939,6 +1940,7 @@ static void DeviceLoadTest(void)
{
diff_count = 0;
diff_count2 = 0;
+ diff_count3 = 0;
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
ddsd.dwSize = sizeof(ddsd);
@@ -1953,6 +1955,9 @@ static void DeviceLoadTest(void)
for (x = 0; x < ddsd.dwWidth; x++)
{
DWORD color = *textureRow++;
+ DWORD r = (color & 0xff0000) >> 16;
+ DWORD g = (color & 0xff00) >> 8;
+ DWORD b = (color & 0xff);
if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
@@ -1961,10 +1966,6 @@ static void DeviceLoadTest(void)
}
else
{
- DWORD r = (color & 0xff0000) >> 16;
- DWORD g = (color & 0xff00) >> 8;
- DWORD b = (color & 0xff);
-
if (r != (0xf0 | i1) || g != x + loadrect.left - loadpoint.x ||
b != y + loadrect.top - loadpoint.y) diff_count++;
}
@@ -1978,21 +1979,29 @@ static void DeviceLoadTest(void)
}
else
{
- DWORD r = (color & 0xff0000) >> 16;
- DWORD g = (color & 0xff00) >> 8;
- DWORD b = (color & 0xff);
-
if (r != (0xf0 | i1) || !IS_VALUE_NEAR(g, x + loadrect.left - loadpoint.x) ||
!IS_VALUE_NEAR(b, y + loadrect.top - loadpoint.y)) diff_count2++;
}
+
+ /* some windows 8 and 10 machines copy the wrong mip */
+ if (x < loadpoint.x / 16 || x >= ceil((loadpoint.x + loadrect.right - loadrect.left) / 16.0) ||
+ y < loadpoint.y / 16 || y >= ceil((loadpoint.y + loadrect.bottom - loadrect.top) / 16.0))
+ {
+ if (color & 0xffffff) diff_count3++;
+ }
+ else
+ {
+ if (r != (0xf0 | (i1 + 4)) || g != x || b != y) diff_count3++;
+ }
}
}
hr = IDirectDrawSurface7_Unlock(texture_levels[1][i1], NULL);
ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
- ok(diff_count == 0 || diff_count2 == 0, "Unexpected destination texture level pixels; %u differences at %d level\n",
- MIN(diff_count, diff_count2), i1);
+ ok(diff_count == 0 || diff_count2 == 0 || broken(diff_count3 == 0),
+ "Unexpected destination texture level pixels; %u differences, %d level\n",
+ MIN(MIN(diff_count, diff_count2), diff_count3), i1);
loadpoint.x /= 2;
loadpoint.y /= 2;
@@ -2145,6 +2154,7 @@ static void DeviceLoadTest(void)
skip("IDirect3DDevice7_Load is broken (happens on some modern Windows installations like XP). Skipping affected tests.\n");
} else {
diff_count = 0;
+ diff_count3 = 0;
for (y = 0 ; y < ddsd.dwHeight; y++)
{
@@ -2153,6 +2163,9 @@ static void DeviceLoadTest(void)
for (x = 0; x < ddsd.dwWidth; x++)
{
DWORD color = *textureRow++;
+ DWORD r = (color & 0xff0000) >> 16;
+ DWORD g = (color & 0xff00) >> 8;
+ DWORD b = (color & 0xff);
if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
@@ -2161,13 +2174,20 @@ static void DeviceLoadTest(void)
}
else
{
- DWORD r = (color & 0xff0000) >> 16;
- DWORD g = (color & 0xff00) >> 8;
- DWORD b = (color & 0xff);
-
if (r != (0xf0 | 2) || g != x + loadrect.left - loadpoint.x ||
b != y + loadrect.top - loadpoint.y) diff_count++;
}
+
+ /* some windows 8 and 10 machines copy the wrong mip */
+ if (x < loadpoint.x / 16 || x >= (loadpoint.x + loadrect.right - loadrect.left) / 16 ||
+ y < loadpoint.y / 16 || y >= (loadpoint.y + loadrect.bottom - loadrect.top) / 16)
+ {
+ if (color & 0xffffff) diff_count3++;
+ }
+ else
+ {
+ if (r != 0xf7 || g != x || b != y) diff_count3++;
+ }
}
}
}
@@ -2175,7 +2195,9 @@ static void DeviceLoadTest(void)
hr = IDirectDrawSurface7_Unlock(texture_levels[1][0], NULL);
ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
- ok(diff_count == 0, "Unexpected destination texture level pixels; %u differences\n", diff_count);
+ ok(diff_count == 0 || broken(diff_count3 == 0),
+ "Unexpected destination texture level pixels; %u differences\n",
+ MIN(diff_count, diff_count3));
for (i = 0; i < 2; i++)
{
@@ -2287,6 +2309,7 @@ static void DeviceLoadTest(void)
if (ddsd.dwWidth == ddsd2.dwWidth && ddsd.dwHeight == ddsd2.dwHeight)
{
diff_count = 0;
+ diff_count3 = 0;
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
ddsd.dwSize = sizeof(ddsd);
@@ -2301,6 +2324,9 @@ static void DeviceLoadTest(void)
for (x = 0; x < ddsd.dwWidth; x++)
{
DWORD color = *textureRow++;
+ DWORD r = (color & 0xff0000) >> 16;
+ DWORD g = (color & 0xff00) >> 8;
+ DWORD b = (color & 0xff);
if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
@@ -2309,20 +2335,29 @@ static void DeviceLoadTest(void)
}
else
{
- DWORD r = (color & 0xff0000) >> 16;
- DWORD g = (color & 0xff00) >> 8;
- DWORD b = (color & 0xff);
-
if (r != (0xf0 | i1) || g != x + loadrect.left - loadpoint.x ||
b != y + loadrect.top - loadpoint.y) diff_count++;
}
+
+ /* some windows 8 and 10 machines copy the wrong mip */
+ if (x < loadpoint.x / 16 || x >= ceil((loadpoint.x + loadrect.right - loadrect.left) / 16.0) ||
+ y < loadpoint.y / 16 || y >= ceil((loadpoint.y + loadrect.bottom - loadrect.top) / 16.0))
+ {
+ if (color & 0xffffff) diff_count3++;
+ }
+ else
+ {
+ if (r != (0xf0 | (i + 4)) || g != x || b != y) diff_count3++;
+ }
}
}
hr = IDirectDrawSurface7_Unlock(texture_levels[1][i], NULL);
ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
- ok(diff_count == 0, "Unexpected destination texture level pixels; %u differences at %d level\n", diff_count, i1);
+ ok(diff_count == 0 || broken(diff_count3 == 0),
+ "Unexpected destination texture level pixels; %u differences at %d level\n",
+ MIN(diff_count, diff_count3), i1);
i++;
}
--
2.16.2
2
3
Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=45317
Signed-off-by: Vincent Povirk <vincent(a)codeweavers.com>
---
dlls/appwiz.cpl/addons.c | 4 ++--
dlls/mscoree/mscoree_main.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c
index aede3d04c02..4e874671f23 100644
--- a/dlls/appwiz.cpl/addons.c
+++ b/dlls/appwiz.cpl/addons.c
@@ -65,8 +65,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
#define GECKO_SHA "???"
#endif
-#define MONO_VERSION "4.7.1"
-#define MONO_SHA "2c8d5db7f833c3413b2519991f5af1f433d59a927564ec6f38a3f1f8b2c629aa"
+#define MONO_VERSION "4.7.3"
+#define MONO_SHA "d24a8017371c7e8224a1778bb43a113ed7ed9720efd9d0cda175d42db6106d3a"
typedef struct {
const char *version;
diff --git a/dlls/mscoree/mscoree_main.c b/dlls/mscoree/mscoree_main.c
index c4876fe1331..eda380a1cad 100644
--- a/dlls/mscoree/mscoree_main.c
+++ b/dlls/mscoree/mscoree_main.c
@@ -682,7 +682,7 @@ static BOOL install_wine_mono(void)
LONG len;
BOOL ret;
- static const char* mono_version = "4.7.1";
+ static const char* mono_version = "4.7.3";
static const char* mono_upgrade_code = "{DE624609-C6B5-486A-9274-EF0B854F6BC5}";
static const WCHAR controlW[] = {'\\','c','o','n','t','r','o','l','.','e','x','e',0};
--
2.17.1
1
0
[PATCH 1/2] mscoree: Use upgrade code to find installed Wine Mono version.
by Vincent Povirk 16 Jul '18
by Vincent Povirk 16 Jul '18
16 Jul '18
Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=45317
Signed-off-by: Vincent Povirk <vincent(a)codeweavers.com>
---
dlls/mscoree/mscoree_main.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/dlls/mscoree/mscoree_main.c b/dlls/mscoree/mscoree_main.c
index 42f8169a4a8..c4876fe1331 100644
--- a/dlls/mscoree/mscoree_main.c
+++ b/dlls/mscoree/mscoree_main.c
@@ -669,8 +669,10 @@ static BOOL install_wine_mono(void)
{
BOOL is_wow64 = FALSE;
HMODULE hmsi;
+ UINT (WINAPI *pMsiEnumRelatedProductsA)(LPCSTR,DWORD,DWORD,LPSTR);
UINT (WINAPI *pMsiGetProductInfoA)(LPCSTR,LPCSTR,LPSTR,DWORD*);
char versionstringbuf[15];
+ char productcodebuf[39];
UINT res;
DWORD buffer_size;
PROCESS_INFORMATION pi;
@@ -681,7 +683,7 @@ static BOOL install_wine_mono(void)
BOOL ret;
static const char* mono_version = "4.7.1";
- static const char* mono_product_code = "{E45D8920-A758-4088-B6C6-31DBB276992E}";
+ static const char* mono_upgrade_code = "{DE624609-C6B5-486A-9274-EF0B854F6BC5}";
static const WCHAR controlW[] = {'\\','c','o','n','t','r','o','l','.','e','x','e',0};
static const WCHAR argsW[] =
@@ -703,11 +705,22 @@ static BOOL install_wine_mono(void)
return FALSE;
}
- pMsiGetProductInfoA = (void*)GetProcAddress(hmsi, "MsiGetProductInfoA");
+ pMsiEnumRelatedProductsA = (void*)GetProcAddress(hmsi, "MsiEnumRelatedProductsA");
- buffer_size = sizeof(versionstringbuf);
+ res = pMsiEnumRelatedProductsA(mono_upgrade_code, 0, 0, productcodebuf);
- res = pMsiGetProductInfoA(mono_product_code, "VersionString", versionstringbuf, &buffer_size);
+ if (res == ERROR_SUCCESS)
+ {
+ pMsiGetProductInfoA = (void*)GetProcAddress(hmsi, "MsiGetProductInfoA");
+
+ buffer_size = sizeof(versionstringbuf);
+
+ res = pMsiGetProductInfoA(productcodebuf, "VersionString", versionstringbuf, &buffer_size);
+ }
+ else if (res != ERROR_NO_MORE_ITEMS)
+ {
+ ERR("MsiEnumRelatedProducts failed, err=%u\n", res);
+ }
FreeLibrary(hmsi);
--
2.17.1
1
0
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmband/dmobject.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++
dlls/dmband/dmobject.h | 53 ++++++++++++
dlls/dmcompos/dmobject.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++
dlls/dmcompos/dmobject.h | 53 ++++++++++++
dlls/dmloader/dmobject.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++
dlls/dmloader/dmobject.h | 53 ++++++++++++
dlls/dmscript/dmobject.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++
dlls/dmscript/dmobject.h | 53 ++++++++++++
dlls/dmstyle/dmobject.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++
dlls/dmstyle/dmobject.h | 53 ++++++++++++
dlls/dmusic/dmobject.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++
dlls/dmusic/dmobject.h | 53 ++++++++++++
dlls/dswave/dmobject.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++
dlls/dswave/dmobject.h | 53 ++++++++++++
14 files changed, 1855 insertions(+)
diff --git a/dlls/dmband/dmobject.c b/dlls/dmband/dmobject.c
index cabb6f74db..25f3198d2b 100644
--- a/dlls/dmband/dmobject.c
+++ b/dlls/dmband/dmobject.c
@@ -21,12 +21,152 @@
*/
#define COBJMACROS
+#include <assert.h>
#include "objbase.h"
#include "dmusici.h"
+#include "dmusicf.h"
#include "dmobject.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
+WINE_DECLARE_DEBUG_CHANNEL(dmfile);
+
+/* RIFF format parsing */
+#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
+
+static inline const char *debugstr_fourcc(DWORD fourcc)
+{
+ if (!fourcc) return "''";
+ return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8),
+ (char)(fourcc >> 16), (char)(fourcc >> 24));
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk)
+{
+ const char *type = "";
+
+ if (!chunk)
+ return "(null)";
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type));
+ return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk->id), type, chunk->size);
+}
+
+static HRESULT stream_read(IStream *stream, void *data, ULONG size)
+{
+ ULONG read;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, data, size, &read);
+ if (FAILED(hr))
+ TRACE_(dmfile)("IStream_Read failed: %08x\n", hr);
+ else if (!read && read < size) {
+ /* All or nothing: Handle a partial read due to end of stream as an error */
+ TRACE_(dmfile)("Short read: %u < %u\n", read, size);
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ static const LARGE_INTEGER zero;
+ ULONGLONG ck_end = 0, p_end = 0;
+ HRESULT hr;
+
+ hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
+ if (FAILED(hr))
+ return hr;
+ assert(!(chunk->offset.QuadPart & 1));
+ if (chunk->parent) {
+ p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
+ if (chunk->offset.QuadPart == p_end)
+ return S_FALSE;
+ ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
+ if (hr != S_OK)
+ return hr;
+ if (chunk->parent) {
+ ck_end += (chunk->size + 1) & ~1;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
+ hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
+ if (hr != S_OK)
+ return hr != S_FALSE ? hr : E_FAIL;
+ }
+
+ TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
+
+ return S_OK;
+}
+
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ LARGE_INTEGER end;
+
+ end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1;
+
+ return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL);
+}
+
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ HRESULT hr;
+
+ if (chunk->id) {
+ hr = stream_skip_chunk(stream, chunk);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return stream_get_chunk(stream, chunk);
+}
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size)
+{
+ if (chunk->size != size) {
+ WARN_(dmfile)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
+ debugstr_fourcc(chunk->id), chunk->size,
+ wine_dbgstr_longlong(chunk->offset.QuadPart), size);
+ return E_FAIL;
+ }
+ return stream_read(stream, data, size);
+}
+
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size)
+{
+ ULONG len;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, str, min(chunk->size, size), &len);
+ if (FAILED(hr))
+ return hr;
+
+ /* Don't assume the string is properly zero terminated */
+ str[min(len, size - 1)] = 0;
+
+ if (len < chunk->size)
+ return S_FALSE;
+ return S_OK;
+}
+
+
/* Generic IDirectMusicObject methods */
static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
@@ -110,6 +250,78 @@ HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
return ret;
}
+/* Helper for IDirectMusicObject::ParseDescriptor */
+static inline void info_get_name(IStream *stream, const struct chunk_entry *info,
+ DMUS_OBJECTDESC *desc)
+{
+ struct chunk_entry chunk = {.parent = info};
+ char name[DMUS_MAX_NAME];
+ ULONG len;
+ HRESULT hr = E_FAIL;
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == mmioFOURCC('I','N','A','M'))
+ hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len);
+
+ if (SUCCEEDED(hr)) {
+ len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName));
+ desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0;
+ desc->dwValidData |= DMUS_OBJ_NAME;
+ }
+}
+
+static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo,
+ DMUS_OBJECTDESC *desc, BOOL inam)
+{
+ struct chunk_entry chunk = {.parent = unfo};
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M')))
+ if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
+}
+
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported)
+{
+ struct chunk_entry chunk = {.parent = riff};
+ HRESULT hr;
+
+ TRACE("Looking for %#x in %p: %s\n", supported, stream, debugstr_chunk(riff));
+
+ desc->dwValidData = 0;
+ desc->dwSize = sizeof(*desc);
+
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
+ switch (chunk.id) {
+ case DMUS_FOURCC_GUID_CHUNK:
+ if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
+ &desc->guidObject, sizeof(desc->guidObject)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_OBJECT;
+ break;
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_VERSION_CHUNK:
+ if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
+ &desc->vVersion, sizeof(desc->vVersion)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_VERSION;
+ break;
+ case FOURCC_LIST:
+ if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME))
+ unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM);
+ else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO))
+ info_get_name(stream, &chunk, desc);
+ break;
+ }
+ }
+ TRACE("Found %#x\n", desc->dwValidData);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmband/dmobject.h b/dlls/dmband/dmobject.h
index ad6bf6d14c..4a721cc152 100644
--- a/dlls/dmband/dmobject.h
+++ b/dlls/dmband/dmobject.h
@@ -19,6 +19,51 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "wine/debug.h"
+
+/* RIFF stream parsing */
+struct chunk_entry;
+struct chunk_entry {
+ FOURCC id;
+ DWORD size;
+ FOURCC type; /* valid only for LIST and RIFF chunks */
+ ULARGE_INTEGER offset; /* chunk offset from start of stream */
+ const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */
+};
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size) DECLSPEC_HIDDEN;
+
+static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD);
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ offset.QuadPart += sizeof(FOURCC);
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart;
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+
+/* IDirectMusicObject base object */
struct dmobject {
IDirectMusicObject IDirectMusicObject_iface;
IPersistStream IPersistStream_iface;
@@ -38,6 +83,14 @@ HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface,
HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN;
+/* Helper for IDirectMusicObject::ParseDescriptor */
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN;
+/* Additional supported flags for dmobj_parsedescriptor.
+ DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmcompos/dmobject.c b/dlls/dmcompos/dmobject.c
index cabb6f74db..25f3198d2b 100644
--- a/dlls/dmcompos/dmobject.c
+++ b/dlls/dmcompos/dmobject.c
@@ -21,12 +21,152 @@
*/
#define COBJMACROS
+#include <assert.h>
#include "objbase.h"
#include "dmusici.h"
+#include "dmusicf.h"
#include "dmobject.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
+WINE_DECLARE_DEBUG_CHANNEL(dmfile);
+
+/* RIFF format parsing */
+#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
+
+static inline const char *debugstr_fourcc(DWORD fourcc)
+{
+ if (!fourcc) return "''";
+ return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8),
+ (char)(fourcc >> 16), (char)(fourcc >> 24));
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk)
+{
+ const char *type = "";
+
+ if (!chunk)
+ return "(null)";
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type));
+ return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk->id), type, chunk->size);
+}
+
+static HRESULT stream_read(IStream *stream, void *data, ULONG size)
+{
+ ULONG read;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, data, size, &read);
+ if (FAILED(hr))
+ TRACE_(dmfile)("IStream_Read failed: %08x\n", hr);
+ else if (!read && read < size) {
+ /* All or nothing: Handle a partial read due to end of stream as an error */
+ TRACE_(dmfile)("Short read: %u < %u\n", read, size);
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ static const LARGE_INTEGER zero;
+ ULONGLONG ck_end = 0, p_end = 0;
+ HRESULT hr;
+
+ hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
+ if (FAILED(hr))
+ return hr;
+ assert(!(chunk->offset.QuadPart & 1));
+ if (chunk->parent) {
+ p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
+ if (chunk->offset.QuadPart == p_end)
+ return S_FALSE;
+ ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
+ if (hr != S_OK)
+ return hr;
+ if (chunk->parent) {
+ ck_end += (chunk->size + 1) & ~1;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
+ hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
+ if (hr != S_OK)
+ return hr != S_FALSE ? hr : E_FAIL;
+ }
+
+ TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
+
+ return S_OK;
+}
+
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ LARGE_INTEGER end;
+
+ end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1;
+
+ return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL);
+}
+
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ HRESULT hr;
+
+ if (chunk->id) {
+ hr = stream_skip_chunk(stream, chunk);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return stream_get_chunk(stream, chunk);
+}
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size)
+{
+ if (chunk->size != size) {
+ WARN_(dmfile)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
+ debugstr_fourcc(chunk->id), chunk->size,
+ wine_dbgstr_longlong(chunk->offset.QuadPart), size);
+ return E_FAIL;
+ }
+ return stream_read(stream, data, size);
+}
+
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size)
+{
+ ULONG len;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, str, min(chunk->size, size), &len);
+ if (FAILED(hr))
+ return hr;
+
+ /* Don't assume the string is properly zero terminated */
+ str[min(len, size - 1)] = 0;
+
+ if (len < chunk->size)
+ return S_FALSE;
+ return S_OK;
+}
+
+
/* Generic IDirectMusicObject methods */
static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
@@ -110,6 +250,78 @@ HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
return ret;
}
+/* Helper for IDirectMusicObject::ParseDescriptor */
+static inline void info_get_name(IStream *stream, const struct chunk_entry *info,
+ DMUS_OBJECTDESC *desc)
+{
+ struct chunk_entry chunk = {.parent = info};
+ char name[DMUS_MAX_NAME];
+ ULONG len;
+ HRESULT hr = E_FAIL;
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == mmioFOURCC('I','N','A','M'))
+ hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len);
+
+ if (SUCCEEDED(hr)) {
+ len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName));
+ desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0;
+ desc->dwValidData |= DMUS_OBJ_NAME;
+ }
+}
+
+static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo,
+ DMUS_OBJECTDESC *desc, BOOL inam)
+{
+ struct chunk_entry chunk = {.parent = unfo};
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M')))
+ if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
+}
+
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported)
+{
+ struct chunk_entry chunk = {.parent = riff};
+ HRESULT hr;
+
+ TRACE("Looking for %#x in %p: %s\n", supported, stream, debugstr_chunk(riff));
+
+ desc->dwValidData = 0;
+ desc->dwSize = sizeof(*desc);
+
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
+ switch (chunk.id) {
+ case DMUS_FOURCC_GUID_CHUNK:
+ if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
+ &desc->guidObject, sizeof(desc->guidObject)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_OBJECT;
+ break;
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_VERSION_CHUNK:
+ if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
+ &desc->vVersion, sizeof(desc->vVersion)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_VERSION;
+ break;
+ case FOURCC_LIST:
+ if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME))
+ unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM);
+ else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO))
+ info_get_name(stream, &chunk, desc);
+ break;
+ }
+ }
+ TRACE("Found %#x\n", desc->dwValidData);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmcompos/dmobject.h b/dlls/dmcompos/dmobject.h
index ad6bf6d14c..4a721cc152 100644
--- a/dlls/dmcompos/dmobject.h
+++ b/dlls/dmcompos/dmobject.h
@@ -19,6 +19,51 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "wine/debug.h"
+
+/* RIFF stream parsing */
+struct chunk_entry;
+struct chunk_entry {
+ FOURCC id;
+ DWORD size;
+ FOURCC type; /* valid only for LIST and RIFF chunks */
+ ULARGE_INTEGER offset; /* chunk offset from start of stream */
+ const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */
+};
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size) DECLSPEC_HIDDEN;
+
+static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD);
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ offset.QuadPart += sizeof(FOURCC);
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart;
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+
+/* IDirectMusicObject base object */
struct dmobject {
IDirectMusicObject IDirectMusicObject_iface;
IPersistStream IPersistStream_iface;
@@ -38,6 +83,14 @@ HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface,
HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN;
+/* Helper for IDirectMusicObject::ParseDescriptor */
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN;
+/* Additional supported flags for dmobj_parsedescriptor.
+ DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmloader/dmobject.c b/dlls/dmloader/dmobject.c
index cabb6f74db..25f3198d2b 100644
--- a/dlls/dmloader/dmobject.c
+++ b/dlls/dmloader/dmobject.c
@@ -21,12 +21,152 @@
*/
#define COBJMACROS
+#include <assert.h>
#include "objbase.h"
#include "dmusici.h"
+#include "dmusicf.h"
#include "dmobject.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
+WINE_DECLARE_DEBUG_CHANNEL(dmfile);
+
+/* RIFF format parsing */
+#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
+
+static inline const char *debugstr_fourcc(DWORD fourcc)
+{
+ if (!fourcc) return "''";
+ return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8),
+ (char)(fourcc >> 16), (char)(fourcc >> 24));
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk)
+{
+ const char *type = "";
+
+ if (!chunk)
+ return "(null)";
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type));
+ return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk->id), type, chunk->size);
+}
+
+static HRESULT stream_read(IStream *stream, void *data, ULONG size)
+{
+ ULONG read;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, data, size, &read);
+ if (FAILED(hr))
+ TRACE_(dmfile)("IStream_Read failed: %08x\n", hr);
+ else if (!read && read < size) {
+ /* All or nothing: Handle a partial read due to end of stream as an error */
+ TRACE_(dmfile)("Short read: %u < %u\n", read, size);
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ static const LARGE_INTEGER zero;
+ ULONGLONG ck_end = 0, p_end = 0;
+ HRESULT hr;
+
+ hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
+ if (FAILED(hr))
+ return hr;
+ assert(!(chunk->offset.QuadPart & 1));
+ if (chunk->parent) {
+ p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
+ if (chunk->offset.QuadPart == p_end)
+ return S_FALSE;
+ ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
+ if (hr != S_OK)
+ return hr;
+ if (chunk->parent) {
+ ck_end += (chunk->size + 1) & ~1;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
+ hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
+ if (hr != S_OK)
+ return hr != S_FALSE ? hr : E_FAIL;
+ }
+
+ TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
+
+ return S_OK;
+}
+
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ LARGE_INTEGER end;
+
+ end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1;
+
+ return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL);
+}
+
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ HRESULT hr;
+
+ if (chunk->id) {
+ hr = stream_skip_chunk(stream, chunk);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return stream_get_chunk(stream, chunk);
+}
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size)
+{
+ if (chunk->size != size) {
+ WARN_(dmfile)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
+ debugstr_fourcc(chunk->id), chunk->size,
+ wine_dbgstr_longlong(chunk->offset.QuadPart), size);
+ return E_FAIL;
+ }
+ return stream_read(stream, data, size);
+}
+
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size)
+{
+ ULONG len;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, str, min(chunk->size, size), &len);
+ if (FAILED(hr))
+ return hr;
+
+ /* Don't assume the string is properly zero terminated */
+ str[min(len, size - 1)] = 0;
+
+ if (len < chunk->size)
+ return S_FALSE;
+ return S_OK;
+}
+
+
/* Generic IDirectMusicObject methods */
static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
@@ -110,6 +250,78 @@ HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
return ret;
}
+/* Helper for IDirectMusicObject::ParseDescriptor */
+static inline void info_get_name(IStream *stream, const struct chunk_entry *info,
+ DMUS_OBJECTDESC *desc)
+{
+ struct chunk_entry chunk = {.parent = info};
+ char name[DMUS_MAX_NAME];
+ ULONG len;
+ HRESULT hr = E_FAIL;
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == mmioFOURCC('I','N','A','M'))
+ hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len);
+
+ if (SUCCEEDED(hr)) {
+ len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName));
+ desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0;
+ desc->dwValidData |= DMUS_OBJ_NAME;
+ }
+}
+
+static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo,
+ DMUS_OBJECTDESC *desc, BOOL inam)
+{
+ struct chunk_entry chunk = {.parent = unfo};
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M')))
+ if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
+}
+
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported)
+{
+ struct chunk_entry chunk = {.parent = riff};
+ HRESULT hr;
+
+ TRACE("Looking for %#x in %p: %s\n", supported, stream, debugstr_chunk(riff));
+
+ desc->dwValidData = 0;
+ desc->dwSize = sizeof(*desc);
+
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
+ switch (chunk.id) {
+ case DMUS_FOURCC_GUID_CHUNK:
+ if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
+ &desc->guidObject, sizeof(desc->guidObject)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_OBJECT;
+ break;
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_VERSION_CHUNK:
+ if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
+ &desc->vVersion, sizeof(desc->vVersion)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_VERSION;
+ break;
+ case FOURCC_LIST:
+ if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME))
+ unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM);
+ else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO))
+ info_get_name(stream, &chunk, desc);
+ break;
+ }
+ }
+ TRACE("Found %#x\n", desc->dwValidData);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmloader/dmobject.h b/dlls/dmloader/dmobject.h
index ad6bf6d14c..4a721cc152 100644
--- a/dlls/dmloader/dmobject.h
+++ b/dlls/dmloader/dmobject.h
@@ -19,6 +19,51 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "wine/debug.h"
+
+/* RIFF stream parsing */
+struct chunk_entry;
+struct chunk_entry {
+ FOURCC id;
+ DWORD size;
+ FOURCC type; /* valid only for LIST and RIFF chunks */
+ ULARGE_INTEGER offset; /* chunk offset from start of stream */
+ const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */
+};
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size) DECLSPEC_HIDDEN;
+
+static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD);
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ offset.QuadPart += sizeof(FOURCC);
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart;
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+
+/* IDirectMusicObject base object */
struct dmobject {
IDirectMusicObject IDirectMusicObject_iface;
IPersistStream IPersistStream_iface;
@@ -38,6 +83,14 @@ HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface,
HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN;
+/* Helper for IDirectMusicObject::ParseDescriptor */
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN;
+/* Additional supported flags for dmobj_parsedescriptor.
+ DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmscript/dmobject.c b/dlls/dmscript/dmobject.c
index cabb6f74db..25f3198d2b 100644
--- a/dlls/dmscript/dmobject.c
+++ b/dlls/dmscript/dmobject.c
@@ -21,12 +21,152 @@
*/
#define COBJMACROS
+#include <assert.h>
#include "objbase.h"
#include "dmusici.h"
+#include "dmusicf.h"
#include "dmobject.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
+WINE_DECLARE_DEBUG_CHANNEL(dmfile);
+
+/* RIFF format parsing */
+#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
+
+static inline const char *debugstr_fourcc(DWORD fourcc)
+{
+ if (!fourcc) return "''";
+ return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8),
+ (char)(fourcc >> 16), (char)(fourcc >> 24));
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk)
+{
+ const char *type = "";
+
+ if (!chunk)
+ return "(null)";
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type));
+ return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk->id), type, chunk->size);
+}
+
+static HRESULT stream_read(IStream *stream, void *data, ULONG size)
+{
+ ULONG read;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, data, size, &read);
+ if (FAILED(hr))
+ TRACE_(dmfile)("IStream_Read failed: %08x\n", hr);
+ else if (!read && read < size) {
+ /* All or nothing: Handle a partial read due to end of stream as an error */
+ TRACE_(dmfile)("Short read: %u < %u\n", read, size);
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ static const LARGE_INTEGER zero;
+ ULONGLONG ck_end = 0, p_end = 0;
+ HRESULT hr;
+
+ hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
+ if (FAILED(hr))
+ return hr;
+ assert(!(chunk->offset.QuadPart & 1));
+ if (chunk->parent) {
+ p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
+ if (chunk->offset.QuadPart == p_end)
+ return S_FALSE;
+ ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
+ if (hr != S_OK)
+ return hr;
+ if (chunk->parent) {
+ ck_end += (chunk->size + 1) & ~1;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
+ hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
+ if (hr != S_OK)
+ return hr != S_FALSE ? hr : E_FAIL;
+ }
+
+ TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
+
+ return S_OK;
+}
+
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ LARGE_INTEGER end;
+
+ end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1;
+
+ return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL);
+}
+
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ HRESULT hr;
+
+ if (chunk->id) {
+ hr = stream_skip_chunk(stream, chunk);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return stream_get_chunk(stream, chunk);
+}
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size)
+{
+ if (chunk->size != size) {
+ WARN_(dmfile)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
+ debugstr_fourcc(chunk->id), chunk->size,
+ wine_dbgstr_longlong(chunk->offset.QuadPart), size);
+ return E_FAIL;
+ }
+ return stream_read(stream, data, size);
+}
+
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size)
+{
+ ULONG len;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, str, min(chunk->size, size), &len);
+ if (FAILED(hr))
+ return hr;
+
+ /* Don't assume the string is properly zero terminated */
+ str[min(len, size - 1)] = 0;
+
+ if (len < chunk->size)
+ return S_FALSE;
+ return S_OK;
+}
+
+
/* Generic IDirectMusicObject methods */
static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
@@ -110,6 +250,78 @@ HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
return ret;
}
+/* Helper for IDirectMusicObject::ParseDescriptor */
+static inline void info_get_name(IStream *stream, const struct chunk_entry *info,
+ DMUS_OBJECTDESC *desc)
+{
+ struct chunk_entry chunk = {.parent = info};
+ char name[DMUS_MAX_NAME];
+ ULONG len;
+ HRESULT hr = E_FAIL;
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == mmioFOURCC('I','N','A','M'))
+ hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len);
+
+ if (SUCCEEDED(hr)) {
+ len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName));
+ desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0;
+ desc->dwValidData |= DMUS_OBJ_NAME;
+ }
+}
+
+static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo,
+ DMUS_OBJECTDESC *desc, BOOL inam)
+{
+ struct chunk_entry chunk = {.parent = unfo};
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M')))
+ if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
+}
+
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported)
+{
+ struct chunk_entry chunk = {.parent = riff};
+ HRESULT hr;
+
+ TRACE("Looking for %#x in %p: %s\n", supported, stream, debugstr_chunk(riff));
+
+ desc->dwValidData = 0;
+ desc->dwSize = sizeof(*desc);
+
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
+ switch (chunk.id) {
+ case DMUS_FOURCC_GUID_CHUNK:
+ if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
+ &desc->guidObject, sizeof(desc->guidObject)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_OBJECT;
+ break;
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_VERSION_CHUNK:
+ if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
+ &desc->vVersion, sizeof(desc->vVersion)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_VERSION;
+ break;
+ case FOURCC_LIST:
+ if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME))
+ unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM);
+ else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO))
+ info_get_name(stream, &chunk, desc);
+ break;
+ }
+ }
+ TRACE("Found %#x\n", desc->dwValidData);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmscript/dmobject.h b/dlls/dmscript/dmobject.h
index ad6bf6d14c..4a721cc152 100644
--- a/dlls/dmscript/dmobject.h
+++ b/dlls/dmscript/dmobject.h
@@ -19,6 +19,51 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "wine/debug.h"
+
+/* RIFF stream parsing */
+struct chunk_entry;
+struct chunk_entry {
+ FOURCC id;
+ DWORD size;
+ FOURCC type; /* valid only for LIST and RIFF chunks */
+ ULARGE_INTEGER offset; /* chunk offset from start of stream */
+ const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */
+};
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size) DECLSPEC_HIDDEN;
+
+static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD);
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ offset.QuadPart += sizeof(FOURCC);
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart;
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+
+/* IDirectMusicObject base object */
struct dmobject {
IDirectMusicObject IDirectMusicObject_iface;
IPersistStream IPersistStream_iface;
@@ -38,6 +83,14 @@ HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface,
HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN;
+/* Helper for IDirectMusicObject::ParseDescriptor */
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN;
+/* Additional supported flags for dmobj_parsedescriptor.
+ DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmstyle/dmobject.c b/dlls/dmstyle/dmobject.c
index cabb6f74db..25f3198d2b 100644
--- a/dlls/dmstyle/dmobject.c
+++ b/dlls/dmstyle/dmobject.c
@@ -21,12 +21,152 @@
*/
#define COBJMACROS
+#include <assert.h>
#include "objbase.h"
#include "dmusici.h"
+#include "dmusicf.h"
#include "dmobject.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
+WINE_DECLARE_DEBUG_CHANNEL(dmfile);
+
+/* RIFF format parsing */
+#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
+
+static inline const char *debugstr_fourcc(DWORD fourcc)
+{
+ if (!fourcc) return "''";
+ return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8),
+ (char)(fourcc >> 16), (char)(fourcc >> 24));
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk)
+{
+ const char *type = "";
+
+ if (!chunk)
+ return "(null)";
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type));
+ return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk->id), type, chunk->size);
+}
+
+static HRESULT stream_read(IStream *stream, void *data, ULONG size)
+{
+ ULONG read;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, data, size, &read);
+ if (FAILED(hr))
+ TRACE_(dmfile)("IStream_Read failed: %08x\n", hr);
+ else if (!read && read < size) {
+ /* All or nothing: Handle a partial read due to end of stream as an error */
+ TRACE_(dmfile)("Short read: %u < %u\n", read, size);
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ static const LARGE_INTEGER zero;
+ ULONGLONG ck_end = 0, p_end = 0;
+ HRESULT hr;
+
+ hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
+ if (FAILED(hr))
+ return hr;
+ assert(!(chunk->offset.QuadPart & 1));
+ if (chunk->parent) {
+ p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
+ if (chunk->offset.QuadPart == p_end)
+ return S_FALSE;
+ ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
+ if (hr != S_OK)
+ return hr;
+ if (chunk->parent) {
+ ck_end += (chunk->size + 1) & ~1;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
+ hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
+ if (hr != S_OK)
+ return hr != S_FALSE ? hr : E_FAIL;
+ }
+
+ TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
+
+ return S_OK;
+}
+
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ LARGE_INTEGER end;
+
+ end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1;
+
+ return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL);
+}
+
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ HRESULT hr;
+
+ if (chunk->id) {
+ hr = stream_skip_chunk(stream, chunk);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return stream_get_chunk(stream, chunk);
+}
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size)
+{
+ if (chunk->size != size) {
+ WARN_(dmfile)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
+ debugstr_fourcc(chunk->id), chunk->size,
+ wine_dbgstr_longlong(chunk->offset.QuadPart), size);
+ return E_FAIL;
+ }
+ return stream_read(stream, data, size);
+}
+
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size)
+{
+ ULONG len;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, str, min(chunk->size, size), &len);
+ if (FAILED(hr))
+ return hr;
+
+ /* Don't assume the string is properly zero terminated */
+ str[min(len, size - 1)] = 0;
+
+ if (len < chunk->size)
+ return S_FALSE;
+ return S_OK;
+}
+
+
/* Generic IDirectMusicObject methods */
static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
@@ -110,6 +250,78 @@ HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
return ret;
}
+/* Helper for IDirectMusicObject::ParseDescriptor */
+static inline void info_get_name(IStream *stream, const struct chunk_entry *info,
+ DMUS_OBJECTDESC *desc)
+{
+ struct chunk_entry chunk = {.parent = info};
+ char name[DMUS_MAX_NAME];
+ ULONG len;
+ HRESULT hr = E_FAIL;
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == mmioFOURCC('I','N','A','M'))
+ hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len);
+
+ if (SUCCEEDED(hr)) {
+ len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName));
+ desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0;
+ desc->dwValidData |= DMUS_OBJ_NAME;
+ }
+}
+
+static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo,
+ DMUS_OBJECTDESC *desc, BOOL inam)
+{
+ struct chunk_entry chunk = {.parent = unfo};
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M')))
+ if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
+}
+
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported)
+{
+ struct chunk_entry chunk = {.parent = riff};
+ HRESULT hr;
+
+ TRACE("Looking for %#x in %p: %s\n", supported, stream, debugstr_chunk(riff));
+
+ desc->dwValidData = 0;
+ desc->dwSize = sizeof(*desc);
+
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
+ switch (chunk.id) {
+ case DMUS_FOURCC_GUID_CHUNK:
+ if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
+ &desc->guidObject, sizeof(desc->guidObject)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_OBJECT;
+ break;
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_VERSION_CHUNK:
+ if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
+ &desc->vVersion, sizeof(desc->vVersion)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_VERSION;
+ break;
+ case FOURCC_LIST:
+ if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME))
+ unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM);
+ else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO))
+ info_get_name(stream, &chunk, desc);
+ break;
+ }
+ }
+ TRACE("Found %#x\n", desc->dwValidData);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmstyle/dmobject.h b/dlls/dmstyle/dmobject.h
index ad6bf6d14c..4a721cc152 100644
--- a/dlls/dmstyle/dmobject.h
+++ b/dlls/dmstyle/dmobject.h
@@ -19,6 +19,51 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "wine/debug.h"
+
+/* RIFF stream parsing */
+struct chunk_entry;
+struct chunk_entry {
+ FOURCC id;
+ DWORD size;
+ FOURCC type; /* valid only for LIST and RIFF chunks */
+ ULARGE_INTEGER offset; /* chunk offset from start of stream */
+ const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */
+};
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size) DECLSPEC_HIDDEN;
+
+static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD);
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ offset.QuadPart += sizeof(FOURCC);
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart;
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+
+/* IDirectMusicObject base object */
struct dmobject {
IDirectMusicObject IDirectMusicObject_iface;
IPersistStream IPersistStream_iface;
@@ -38,6 +83,14 @@ HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface,
HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN;
+/* Helper for IDirectMusicObject::ParseDescriptor */
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN;
+/* Additional supported flags for dmobj_parsedescriptor.
+ DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmusic/dmobject.c b/dlls/dmusic/dmobject.c
index cabb6f74db..25f3198d2b 100644
--- a/dlls/dmusic/dmobject.c
+++ b/dlls/dmusic/dmobject.c
@@ -21,12 +21,152 @@
*/
#define COBJMACROS
+#include <assert.h>
#include "objbase.h"
#include "dmusici.h"
+#include "dmusicf.h"
#include "dmobject.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
+WINE_DECLARE_DEBUG_CHANNEL(dmfile);
+
+/* RIFF format parsing */
+#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
+
+static inline const char *debugstr_fourcc(DWORD fourcc)
+{
+ if (!fourcc) return "''";
+ return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8),
+ (char)(fourcc >> 16), (char)(fourcc >> 24));
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk)
+{
+ const char *type = "";
+
+ if (!chunk)
+ return "(null)";
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type));
+ return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk->id), type, chunk->size);
+}
+
+static HRESULT stream_read(IStream *stream, void *data, ULONG size)
+{
+ ULONG read;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, data, size, &read);
+ if (FAILED(hr))
+ TRACE_(dmfile)("IStream_Read failed: %08x\n", hr);
+ else if (!read && read < size) {
+ /* All or nothing: Handle a partial read due to end of stream as an error */
+ TRACE_(dmfile)("Short read: %u < %u\n", read, size);
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ static const LARGE_INTEGER zero;
+ ULONGLONG ck_end = 0, p_end = 0;
+ HRESULT hr;
+
+ hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
+ if (FAILED(hr))
+ return hr;
+ assert(!(chunk->offset.QuadPart & 1));
+ if (chunk->parent) {
+ p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
+ if (chunk->offset.QuadPart == p_end)
+ return S_FALSE;
+ ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
+ if (hr != S_OK)
+ return hr;
+ if (chunk->parent) {
+ ck_end += (chunk->size + 1) & ~1;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
+ hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
+ if (hr != S_OK)
+ return hr != S_FALSE ? hr : E_FAIL;
+ }
+
+ TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
+
+ return S_OK;
+}
+
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ LARGE_INTEGER end;
+
+ end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1;
+
+ return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL);
+}
+
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ HRESULT hr;
+
+ if (chunk->id) {
+ hr = stream_skip_chunk(stream, chunk);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return stream_get_chunk(stream, chunk);
+}
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size)
+{
+ if (chunk->size != size) {
+ WARN_(dmfile)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
+ debugstr_fourcc(chunk->id), chunk->size,
+ wine_dbgstr_longlong(chunk->offset.QuadPart), size);
+ return E_FAIL;
+ }
+ return stream_read(stream, data, size);
+}
+
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size)
+{
+ ULONG len;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, str, min(chunk->size, size), &len);
+ if (FAILED(hr))
+ return hr;
+
+ /* Don't assume the string is properly zero terminated */
+ str[min(len, size - 1)] = 0;
+
+ if (len < chunk->size)
+ return S_FALSE;
+ return S_OK;
+}
+
+
/* Generic IDirectMusicObject methods */
static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
@@ -110,6 +250,78 @@ HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
return ret;
}
+/* Helper for IDirectMusicObject::ParseDescriptor */
+static inline void info_get_name(IStream *stream, const struct chunk_entry *info,
+ DMUS_OBJECTDESC *desc)
+{
+ struct chunk_entry chunk = {.parent = info};
+ char name[DMUS_MAX_NAME];
+ ULONG len;
+ HRESULT hr = E_FAIL;
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == mmioFOURCC('I','N','A','M'))
+ hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len);
+
+ if (SUCCEEDED(hr)) {
+ len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName));
+ desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0;
+ desc->dwValidData |= DMUS_OBJ_NAME;
+ }
+}
+
+static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo,
+ DMUS_OBJECTDESC *desc, BOOL inam)
+{
+ struct chunk_entry chunk = {.parent = unfo};
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M')))
+ if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
+}
+
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported)
+{
+ struct chunk_entry chunk = {.parent = riff};
+ HRESULT hr;
+
+ TRACE("Looking for %#x in %p: %s\n", supported, stream, debugstr_chunk(riff));
+
+ desc->dwValidData = 0;
+ desc->dwSize = sizeof(*desc);
+
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
+ switch (chunk.id) {
+ case DMUS_FOURCC_GUID_CHUNK:
+ if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
+ &desc->guidObject, sizeof(desc->guidObject)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_OBJECT;
+ break;
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_VERSION_CHUNK:
+ if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
+ &desc->vVersion, sizeof(desc->vVersion)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_VERSION;
+ break;
+ case FOURCC_LIST:
+ if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME))
+ unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM);
+ else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO))
+ info_get_name(stream, &chunk, desc);
+ break;
+ }
+ }
+ TRACE("Found %#x\n", desc->dwValidData);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmusic/dmobject.h b/dlls/dmusic/dmobject.h
index ad6bf6d14c..4a721cc152 100644
--- a/dlls/dmusic/dmobject.h
+++ b/dlls/dmusic/dmobject.h
@@ -19,6 +19,51 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "wine/debug.h"
+
+/* RIFF stream parsing */
+struct chunk_entry;
+struct chunk_entry {
+ FOURCC id;
+ DWORD size;
+ FOURCC type; /* valid only for LIST and RIFF chunks */
+ ULARGE_INTEGER offset; /* chunk offset from start of stream */
+ const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */
+};
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size) DECLSPEC_HIDDEN;
+
+static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD);
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ offset.QuadPart += sizeof(FOURCC);
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart;
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+
+/* IDirectMusicObject base object */
struct dmobject {
IDirectMusicObject IDirectMusicObject_iface;
IPersistStream IPersistStream_iface;
@@ -38,6 +83,14 @@ HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface,
HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN;
+/* Helper for IDirectMusicObject::ParseDescriptor */
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN;
+/* Additional supported flags for dmobj_parsedescriptor.
+ DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dswave/dmobject.c b/dlls/dswave/dmobject.c
index cabb6f74db..25f3198d2b 100644
--- a/dlls/dswave/dmobject.c
+++ b/dlls/dswave/dmobject.c
@@ -21,12 +21,152 @@
*/
#define COBJMACROS
+#include <assert.h>
#include "objbase.h"
#include "dmusici.h"
+#include "dmusicf.h"
#include "dmobject.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
+WINE_DECLARE_DEBUG_CHANNEL(dmfile);
+
+/* RIFF format parsing */
+#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
+
+static inline const char *debugstr_fourcc(DWORD fourcc)
+{
+ if (!fourcc) return "''";
+ return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8),
+ (char)(fourcc >> 16), (char)(fourcc >> 24));
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk)
+{
+ const char *type = "";
+
+ if (!chunk)
+ return "(null)";
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type));
+ return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk->id), type, chunk->size);
+}
+
+static HRESULT stream_read(IStream *stream, void *data, ULONG size)
+{
+ ULONG read;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, data, size, &read);
+ if (FAILED(hr))
+ TRACE_(dmfile)("IStream_Read failed: %08x\n", hr);
+ else if (!read && read < size) {
+ /* All or nothing: Handle a partial read due to end of stream as an error */
+ TRACE_(dmfile)("Short read: %u < %u\n", read, size);
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ static const LARGE_INTEGER zero;
+ ULONGLONG ck_end = 0, p_end = 0;
+ HRESULT hr;
+
+ hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
+ if (FAILED(hr))
+ return hr;
+ assert(!(chunk->offset.QuadPart & 1));
+ if (chunk->parent) {
+ p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
+ if (chunk->offset.QuadPart == p_end)
+ return S_FALSE;
+ ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
+ if (hr != S_OK)
+ return hr;
+ if (chunk->parent) {
+ ck_end += (chunk->size + 1) & ~1;
+ if (ck_end > p_end) {
+ WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
+ wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
+ return E_FAIL;
+ }
+ }
+
+ if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
+ hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
+ if (hr != S_OK)
+ return hr != S_FALSE ? hr : E_FAIL;
+ }
+
+ TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
+
+ return S_OK;
+}
+
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ LARGE_INTEGER end;
+
+ end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1;
+
+ return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL);
+}
+
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
+{
+ HRESULT hr;
+
+ if (chunk->id) {
+ hr = stream_skip_chunk(stream, chunk);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return stream_get_chunk(stream, chunk);
+}
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size)
+{
+ if (chunk->size != size) {
+ WARN_(dmfile)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
+ debugstr_fourcc(chunk->id), chunk->size,
+ wine_dbgstr_longlong(chunk->offset.QuadPart), size);
+ return E_FAIL;
+ }
+ return stream_read(stream, data, size);
+}
+
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size)
+{
+ ULONG len;
+ HRESULT hr;
+
+ hr = IStream_Read(stream, str, min(chunk->size, size), &len);
+ if (FAILED(hr))
+ return hr;
+
+ /* Don't assume the string is properly zero terminated */
+ str[min(len, size - 1)] = 0;
+
+ if (len < chunk->size)
+ return S_FALSE;
+ return S_OK;
+}
+
+
/* Generic IDirectMusicObject methods */
static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
@@ -110,6 +250,78 @@ HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
return ret;
}
+/* Helper for IDirectMusicObject::ParseDescriptor */
+static inline void info_get_name(IStream *stream, const struct chunk_entry *info,
+ DMUS_OBJECTDESC *desc)
+{
+ struct chunk_entry chunk = {.parent = info};
+ char name[DMUS_MAX_NAME];
+ ULONG len;
+ HRESULT hr = E_FAIL;
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == mmioFOURCC('I','N','A','M'))
+ hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len);
+
+ if (SUCCEEDED(hr)) {
+ len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName));
+ desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0;
+ desc->dwValidData |= DMUS_OBJ_NAME;
+ }
+}
+
+static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo,
+ DMUS_OBJECTDESC *desc, BOOL inam)
+{
+ struct chunk_entry chunk = {.parent = unfo};
+
+ while (stream_next_chunk(stream, &chunk) == S_OK)
+ if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M')))
+ if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
+}
+
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported)
+{
+ struct chunk_entry chunk = {.parent = riff};
+ HRESULT hr;
+
+ TRACE("Looking for %#x in %p: %s\n", supported, stream, debugstr_chunk(riff));
+
+ desc->dwValidData = 0;
+ desc->dwSize = sizeof(*desc);
+
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
+ switch (chunk.id) {
+ case DMUS_FOURCC_GUID_CHUNK:
+ if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
+ &desc->guidObject, sizeof(desc->guidObject)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_OBJECT;
+ break;
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_VERSION_CHUNK:
+ if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
+ &desc->vVersion, sizeof(desc->vVersion)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_VERSION;
+ break;
+ case FOURCC_LIST:
+ if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME))
+ unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM);
+ else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO))
+ info_get_name(stream, &chunk, desc);
+ break;
+ }
+ }
+ TRACE("Found %#x\n", desc->dwValidData);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dswave/dmobject.h b/dlls/dswave/dmobject.h
index ad6bf6d14c..4a721cc152 100644
--- a/dlls/dswave/dmobject.h
+++ b/dlls/dswave/dmobject.h
@@ -19,6 +19,51 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "wine/debug.h"
+
+/* RIFF stream parsing */
+struct chunk_entry;
+struct chunk_entry {
+ FOURCC id;
+ DWORD size;
+ FOURCC type; /* valid only for LIST and RIFF chunks */
+ ULARGE_INTEGER offset; /* chunk offset from start of stream */
+ const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */
+};
+
+HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
+ ULONG size) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
+ ULONG size) DECLSPEC_HIDDEN;
+
+static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD);
+ if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
+ offset.QuadPart += sizeof(FOURCC);
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk)
+{
+ LARGE_INTEGER offset;
+
+ offset.QuadPart = chunk->offset.QuadPart;
+
+ return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+}
+
+const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+
+
+/* IDirectMusicObject base object */
struct dmobject {
IDirectMusicObject IDirectMusicObject_iface;
IPersistStream IPersistStream_iface;
@@ -38,6 +83,14 @@ HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface,
HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN;
+/* Helper for IDirectMusicObject::ParseDescriptor */
+HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
+ DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN;
+/* Additional supported flags for dmobj_parsedescriptor.
+ DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
+#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
--
2.14.4
2
2
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45393
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
---
.../api-ms-win-crt-stdio-l1-1-0.spec | 2 +-
dlls/msvcr100/msvcr100.spec | 2 +-
dlls/msvcr110/msvcr110.spec | 2 +-
dlls/msvcr120/msvcr120.spec | 2 +-
dlls/msvcr120_app/msvcr120_app.spec | 2 +-
dlls/msvcr80/msvcr80.spec | 2 +-
dlls/msvcr90/msvcr90.spec | 2 +-
dlls/msvcrt/file.c | 66
++++++++++++++--------
dlls/ucrtbase/ucrtbase.spec | 2 +-
9 files changed, 52 insertions(+), 30 deletions(-)
1
0