3 * Copyright (c) 2007-2010 SlimDX Group
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 #include "DataStream.h"
25 #include "Utilities.h"
26 #include "multimedia/WaveStream.h"
28 #include "SlimDXException.h"
30 using namespace System;
31 using namespace System::Collections::Generic;
32 using namespace System::IO;
33 using namespace System::Reflection;
34 using namespace System::Globalization;
35 using namespace SlimDX::Multimedia;
39 Utilities::Utilities()
43 generic<typename T> where T : value class
44 array<T>^ Utilities::ReadRange( ID3DXBuffer *buffer, int count )
47 throw gcnew ArgumentOutOfRangeException( "count" );
52 size_t elementSize = sizeof(T);
53 array<T>^ result = gcnew array<T>( count );
55 pin_ptr<T> pinnedBuffer = &result[0];
56 memcpy( pinnedBuffer, buffer->GetBufferPointer(), count * elementSize );
63 //TODO: This needs review upon interface refactor.
64 GUID Utilities::GetNativeGuidForType( Type^ type )
67 throw gcnew ArgumentNullException( "type" );
69 // This will only work for ComObjects.
70 if( !type->IsSubclassOf( ComObject::typeid ) )
73 // This should never fail (i.e., should never return null) since we now know the type is a ComObject subclass.
74 //TODO: Old comobjects have this private, new ones public. blah blah. this needs to be moved to an attribute anyway
75 // or it won't work with interfaces.
76 PropertyInfo^ nativeInterfaceProperty = type->GetProperty( "NativeInterface", BindingFlags::NonPublic | BindingFlags::Static );
77 if( nativeInterfaceProperty == nullptr )
78 nativeInterfaceProperty = type->GetProperty( "NativeInterface" );
80 Guid nativeInterface = static_cast<Guid>( nativeInterfaceProperty->GetValue( nullptr, nullptr ) );
82 return ConvertManagedGuid( nativeInterface );
85 Guid Utilities::ConvertNativeGuid( const GUID &guid )
87 if( guid == GUID_NULL )
107 GUID Utilities::ConvertManagedGuid( Guid guid )
109 if( guid == Guid::Empty )
113 array<Byte>^ bytes = guid.ToByteArray();
114 pin_ptr<unsigned char> pinned_bytes = &bytes[0];
115 memcpy( &result, pinned_bytes, sizeof(GUID) );
120 int Utilities::SizeOfFormatElement( DXGI_FORMAT format )
124 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
125 case DXGI_FORMAT_R32G32B32A32_FLOAT:
126 case DXGI_FORMAT_R32G32B32A32_UINT:
127 case DXGI_FORMAT_R32G32B32A32_SINT:
130 case DXGI_FORMAT_R32G32B32_TYPELESS:
131 case DXGI_FORMAT_R32G32B32_FLOAT:
132 case DXGI_FORMAT_R32G32B32_UINT:
133 case DXGI_FORMAT_R32G32B32_SINT:
136 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
137 case DXGI_FORMAT_R16G16B16A16_FLOAT:
138 case DXGI_FORMAT_R16G16B16A16_UNORM:
139 case DXGI_FORMAT_R16G16B16A16_UINT:
140 case DXGI_FORMAT_R16G16B16A16_SNORM:
141 case DXGI_FORMAT_R16G16B16A16_SINT:
142 case DXGI_FORMAT_R32G32_TYPELESS:
143 case DXGI_FORMAT_R32G32_FLOAT:
144 case DXGI_FORMAT_R32G32_UINT:
145 case DXGI_FORMAT_R32G32_SINT:
146 case DXGI_FORMAT_R32G8X24_TYPELESS:
147 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
148 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
149 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
152 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
153 case DXGI_FORMAT_R10G10B10A2_UNORM:
154 case DXGI_FORMAT_R10G10B10A2_UINT:
155 case DXGI_FORMAT_R11G11B10_FLOAT:
156 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
157 case DXGI_FORMAT_R8G8B8A8_UNORM:
158 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
159 case DXGI_FORMAT_R8G8B8A8_UINT:
160 case DXGI_FORMAT_R8G8B8A8_SNORM:
161 case DXGI_FORMAT_R8G8B8A8_SINT:
162 case DXGI_FORMAT_R16G16_TYPELESS:
163 case DXGI_FORMAT_R16G16_FLOAT:
164 case DXGI_FORMAT_R16G16_UNORM:
165 case DXGI_FORMAT_R16G16_UINT:
166 case DXGI_FORMAT_R16G16_SNORM:
167 case DXGI_FORMAT_R16G16_SINT:
168 case DXGI_FORMAT_R32_TYPELESS:
169 case DXGI_FORMAT_D32_FLOAT:
170 case DXGI_FORMAT_R32_FLOAT:
171 case DXGI_FORMAT_R32_UINT:
172 case DXGI_FORMAT_R32_SINT:
173 case DXGI_FORMAT_R24G8_TYPELESS:
174 case DXGI_FORMAT_D24_UNORM_S8_UINT:
175 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
176 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
177 case DXGI_FORMAT_B8G8R8A8_UNORM:
178 case DXGI_FORMAT_B8G8R8X8_UNORM:
181 case DXGI_FORMAT_R8G8_TYPELESS:
182 case DXGI_FORMAT_R8G8_UNORM:
183 case DXGI_FORMAT_R8G8_UINT:
184 case DXGI_FORMAT_R8G8_SNORM:
185 case DXGI_FORMAT_R8G8_SINT:
186 case DXGI_FORMAT_R16_TYPELESS:
187 case DXGI_FORMAT_R16_FLOAT:
188 case DXGI_FORMAT_D16_UNORM:
189 case DXGI_FORMAT_R16_UNORM:
190 case DXGI_FORMAT_R16_UINT:
191 case DXGI_FORMAT_R16_SNORM:
192 case DXGI_FORMAT_R16_SINT:
193 case DXGI_FORMAT_B5G6R5_UNORM:
194 case DXGI_FORMAT_B5G5R5A1_UNORM:
197 case DXGI_FORMAT_R8_TYPELESS:
198 case DXGI_FORMAT_R8_UNORM:
199 case DXGI_FORMAT_R8_UINT:
200 case DXGI_FORMAT_R8_SNORM:
201 case DXGI_FORMAT_R8_SINT:
202 case DXGI_FORMAT_A8_UNORM:
205 // Compressed format; http://msdn2.microsoft.com/en-us/library/bb694531(VS.85).aspx
206 case DXGI_FORMAT_BC2_TYPELESS:
207 case DXGI_FORMAT_BC2_UNORM:
208 case DXGI_FORMAT_BC2_UNORM_SRGB:
209 case DXGI_FORMAT_BC3_TYPELESS:
210 case DXGI_FORMAT_BC3_UNORM:
211 case DXGI_FORMAT_BC3_UNORM_SRGB:
212 case DXGI_FORMAT_BC5_TYPELESS:
213 case DXGI_FORMAT_BC5_UNORM:
214 case DXGI_FORMAT_BC5_SNORM:
217 // Compressed format; http://msdn2.microsoft.com/en-us/library/bb694531(VS.85).aspx
218 case DXGI_FORMAT_R1_UNORM:
219 case DXGI_FORMAT_BC1_TYPELESS:
220 case DXGI_FORMAT_BC1_UNORM:
221 case DXGI_FORMAT_BC1_UNORM_SRGB:
222 case DXGI_FORMAT_BC4_TYPELESS:
223 case DXGI_FORMAT_BC4_UNORM:
224 case DXGI_FORMAT_BC4_SNORM:
227 // Compressed format; http://msdn2.microsoft.com/en-us/library/bb694531(VS.85).aspx
228 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
231 // These are compressed, but bit-size information is unclear.
232 case DXGI_FORMAT_R8G8_B8G8_UNORM:
233 case DXGI_FORMAT_G8R8_G8B8_UNORM:
236 case DXGI_FORMAT_UNKNOWN:
238 throw gcnew InvalidOperationException( "Cannot determine format element size; invalid format specified." );
242 Drawing::Rectangle Utilities::ConvertRect(RECT rect)
244 return Drawing::Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
247 void Utilities::ConvertRect(System::Drawing::Rectangle& source, RECT& dest)
249 dest.top = source.Top;
250 dest.bottom = source.Bottom;
251 dest.left = source.Left;
252 dest.right = source.Right;
255 array<Byte>^ Utilities::ReadStream( Stream^ stream, DataStream^* dataStream )
259 return ReadStream( stream, length, dataStream );
262 array<Byte>^ Utilities::ReadStream( Stream^ stream, int% readLength, DataStream^* dataStream )
264 if( stream == nullptr )
265 throw gcnew ArgumentNullException( "stream" );
266 if( !stream->CanRead )
267 throw gcnew NotSupportedException();
269 if( readLength > stream->Length - stream->Position )
270 throw gcnew ArgumentOutOfRangeException( "readLength" );
271 if( readLength == 0 )
272 readLength = static_cast<int>( stream->Length - stream->Position );
274 throw gcnew ArgumentOutOfRangeException( "readLength" );
275 if( readLength == 0 )
276 return gcnew array<Byte>( 0 );
278 //if we're reading a DataStream, don't return anything and send back the casted DataStream
279 DataStream^ ds = dynamic_cast<DataStream^>( stream );
280 if( ds != nullptr && dataStream != NULL )
286 //It turns out this can fail because MemoryStream keeps an exposable parameter, and defaults it to
287 //false, so that most of the time, MemoryStream->GetBuffer() can't be used. We might use reflection
288 //to pull the internal array directly. Until then, MemoryStream can literally GO FUCK ITS OWN INTERFACE.
289 /*//if we're reading an entire memory stream from beginning to end, just return the internal buffer
290 MemoryStream^ ms = dynamic_cast<MemoryStream^>( stream );
291 if( ms != nullptr && stream->Position == 0 && readLength == stream->Length )
293 return ms->GetBuffer();
296 WaveStream^ ws = dynamic_cast<WaveStream^>( stream );
297 if( ws != nullptr && dataStream != NULL && ws->InternalMemory != nullptr )
299 *dataStream = ws->InternalMemory;
303 array<Byte>^ buffer = gcnew array<Byte>( readLength );
305 while( bytesRead < readLength )
306 bytesRead += stream->Read( buffer, bytesRead, readLength - bytesRead );
311 void Utilities::CheckArrayBounds( Array^ data, int offset, int% count )
313 if( data == nullptr )
314 throw gcnew ArgumentNullException( "data" );
316 CheckBounds( 0, data->Length, offset, count );
319 void Utilities::CheckBounds( int lowerBound, int size, int offset, int% count )
321 if( offset < lowerBound )
322 throw gcnew ArgumentOutOfRangeException( "offset" );
324 throw gcnew ArgumentOutOfRangeException( "count" );
325 if( offset + count > size )
326 throw gcnew ArgumentException( "The sum of offset and count is greater than the buffer length." );
329 count = size - offset;
333 bool Utilities::CheckElementEquality( array<T>^ left, array<T>^ right )
335 if( left->Length != right->Length )
338 for( int index = 0; index < left->Length; ++index )
340 if( !left[index]->Equals( right[index] ) )
350 bool Utilities::CheckElementEquality( IList<T>^ left, IList<T>^ right )
352 if( left->Count != right->Count )
355 for( int index = 0; index < left->Count; ++index )
357 if( !left[index]->Equals( right[index] ) )
366 String^ Utilities::BufferToString( ID3DXBuffer *buffer )
370 String^ string = gcnew String( reinterpret_cast<const char*>( buffer->GetBufferPointer() ) );
376 return String::Empty;
380 String^ Utilities::BlobToString( ID3D10Blob *blob )
384 String^ string = gcnew String( reinterpret_cast<const char*>( blob->GetBufferPointer() ) );
389 return String::Empty;
392 void Utilities::FreeNativeString( LPCSTR string )
397 System::Runtime::InteropServices::Marshal::FreeHGlobal( IntPtr( const_cast<void*>( reinterpret_cast<const void*>( string ) ) ) );
400 void Utilities::FreeNativeString( LPSTR string )
405 System::Runtime::InteropServices::Marshal::FreeHGlobal( IntPtr( reinterpret_cast<void*>( string ) ) );
408 LPSTR Utilities::AllocateNativeString( String^ value )
410 if( value == nullptr || String::IsNullOrEmpty( value ) )
413 return reinterpret_cast<LPSTR>( System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi( value ).ToPointer() );
417 T Utilities::FromIntToT( int value )
419 if( T::typeid->IsEnum )
420 return safe_cast<T>( static_cast<int>( value ) );
421 else if( T::typeid == float::typeid )
422 return safe_cast<T>( *reinterpret_cast<float*>( &value ) );
424 return safe_cast<T>( Convert::ChangeType( static_cast<int>( value ), T::typeid, CultureInfo::InvariantCulture ) );