yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
4c76b2759
master
1// unit-test-riff.cpp 2 3#include "../../source/core/slang-random-generator.h" 4#include "../../source/core/slang-riff.h" 5#include "unit-test/slang-unit-test.h" 6 7using namespace Slang ; 8 9static void _writeRandom ( 10RandomGenerator * rand , 11size_t maxSize , 12RIFF ::BuildCursor & cursor , 13List < uint8_t >& ioData ) 14{ 15while (true) 16 { 17const Index oldCount = ioData .getCount (); 18 19const size_t allocSize = size_t (rand -> nextInt32InRange (1 ,50 )); 20 21if (allocSize + oldCount > maxSize ) 22 { 23break ; 24 } 25 26ioData .setCount (oldCount + Index (allocSize )); 27rand -> nextData (ioData .getBuffer ()+ oldCount ,allocSize ); 28 29// Write 30cursor .addData (ioData .getBuffer ()+ oldCount ,allocSize ); 31 } 32 33// Should be a single block with same data as the List 34auto dataChunk = as < RIFF ::DataChunkBuilder > (cursor .getCurrentChunk ()); 35SLANG_ASSERT (dataChunk ); 36} 37 38namespace 39{ 40struct DumpContext 41{ 42private : 43WriterHelper _writer ; 44Count _indent = 0 ; 45Count _hexByteCount = 0 ; 46bool _isRoot = true; 47 48public : 49DumpContext (ISlangWriter * writer ) 50 :_writer (writer ) 51 { 52 } 53 54void beginListChunk (RIFF ::Chunk ::Type type ) 55 { 56_dumpIndent (); 57// If it's the root it's 'riff' 58_dumpRiffType (_isRoot ?RIFF ::RootChunk ::kTag :RIFF ::ListChunk ::kTag ); 59_writer .put (" " ); 60_dumpRiffType (type ); 61_writer .put ("\n" ); 62_indent ++ ; 63 } 64 65void endListChunk () {_indent -- ; } 66 67void beginDataChunk (RIFF ::Chunk ::Type type ) 68 { 69_dumpIndent (); 70// Write out the name 71_dumpRiffType (type ); 72_writer .put ("\n" ); 73_indent ++ ; 74 75_hexByteCount = 0 ; 76 } 77 78void endDataChunk () {_indent -- ; } 79 80void handleData (void const * data ,Size size ) 81 { 82auto cursor = static_cast < Byte const *> (data ); 83auto remainingSize = size ; 84while (remainingSize -- ) 85 { 86auto byte = * cursor ++ ; 87 88static const Count kBytesPerLine = 32 ; 89static const Count kBytesPerCluster = 4 ; 90if (_hexByteCount %kBytesPerLine == 0 ) 91 { 92_writer .put ("\n" ); 93_dumpIndent (); 94 } 95else if (_hexByteCount %kBytesPerCluster == 0 ) 96 { 97_writer .put (" " ); 98 } 99_hexByteCount ++ ; 100 101char text [4 ]= {0 ,0 ,' ' ,0 }; 102 103char const * hexDigits = "0123456789abcdef" ; 104text [0 ]= hexDigits [(byte >>4 )& 0xF ]; 105text [1 ]= hexDigits [(byte >>0 )& 0xF ]; 106 107_writer .put (text ); 108 } 109 } 110 111void _dumpIndent () 112 { 113for (int i = 0 ;i < _indent ;++ i ) 114 { 115_writer .put (" " ); 116 } 117 } 118void _dumpRiffType (FourCC fourCC ) 119 { 120auto rawValue = FourCC ::RawValue (fourCC ); 121 122char text [5 ]; 123for (int i = 0 ;i < 4 ;++ i ) 124 { 125text [i ]= char (rawValue & 0xFF ); 126rawValue >>=8 ; 127 } 128text [4 ]= 0 ; 129_writer .put (text ); 130 } 131}; 132 133}// namespace 134 135static void _dump (RIFF ::Chunk const * chunk ,DumpContext context ) 136{ 137if (auto listChunk = as < RIFF ::ListChunk > (chunk )) 138 { 139context .beginListChunk (listChunk -> getType ()); 140for (auto child :listChunk -> getChildren ()) 141_dump (child ,context ); 142context .endListChunk (); 143 } 144else if (auto dataChunk = as < RIFF ::DataChunk > (chunk )) 145 { 146context .beginDataChunk (dataChunk -> getType ()); 147context .handleData (dataChunk -> getPayload (),dataChunk -> getPayloadSize ()); 148context .endDataChunk (); 149 } 150} 151 152static void _dump (RIFF ::ChunkBuilder * chunk ,DumpContext context ) 153{ 154if (auto listChunk = as < RIFF ::ListChunkBuilder > (chunk )) 155 { 156context .beginListChunk (listChunk -> getType ()); 157for (auto child :listChunk -> getChildren ()) 158_dump (child ,context ); 159context .endListChunk (); 160 } 161else if (auto dataChunk = as < RIFF ::DataChunkBuilder > (chunk )) 162 { 163context .beginDataChunk (dataChunk -> getType ()); 164for (auto shard :dataChunk -> getShards ()) 165context .handleData (shard -> getPayload (),shard -> getPayloadSize ()); 166context .endDataChunk (); 167 } 168} 169 170static bool _isSingleShard (RIFF ::DataChunkBuilder * chunk ) 171{ 172Count count = 0 ; 173for (auto shard :chunk -> getShards ()) 174 { 175count ++ ; 176if (count > 1 ) 177break ; 178 } 179return count == 1 ; 180} 181 182static bool _isEqual (RIFF ::DataChunkBuilder * chunk ,void const * data ,Size size ) 183{ 184auto remainingData = static_cast < Byte const *> (data ); 185auto remainingSize = size ; 186 187for (auto shard :chunk -> getShards ()) 188 { 189// If there is more content in the chunk than remains 190// to compare against, then there is no chance of a match. 191// 192auto shardSize = shard -> getPayloadSize (); 193if (shard -> getPayloadSize ()> remainingSize ) 194 { 195return false; 196 } 197 198// Contents must match, byte-for-byte. 199// 200if (::memcmp (remainingData ,shard -> getPayload (),shardSize )!= 0 ) 201 { 202return false; 203 } 204 205remainingData += shardSize ; 206remainingSize -= shardSize ; 207 } 208 209// If we reach the end of the chunk, then we have 210// a match if there is no data remaining to 211// compare against. 212// 213return remainingSize == 0 ; 214} 215 216SLANG_UNIT_TEST (riff ) 217{ 218const FourCC markThings = SLANG_FOUR_CC ('T' ,'H' ,'I' ,'N' ); 219const FourCC markData = SLANG_FOUR_CC ('D' ,'A' ,'T' ,'A' ); 220 221 { 222RIFF ::Builder riffBuilder ; 223RIFF ::BuildCursor cursor (riffBuilder ); 224 225 { 226SLANG_SCOPED_RIFF_BUILDER_LIST_CHUNK (cursor ,markThings ); 227 { 228SLANG_SCOPED_RIFF_BUILDER_DATA_CHUNK (cursor ,markData ); 229 230const char hello []= "Hello " ; 231const char world []= "World!" ; 232 233cursor .addData (hello ,sizeof (hello )); 234cursor .addData (world ,sizeof (world )); 235 } 236 237 { 238SLANG_SCOPED_RIFF_BUILDER_DATA_CHUNK (cursor ,markData ); 239 240const char test0 []= "Testing... " ; 241const char test1 []= "Testing!" ; 242 243cursor .addData (test0 ,sizeof (test0 )); 244cursor .addData (test1 ,sizeof (test1 )); 245 } 246 247 { 248SLANG_SCOPED_RIFF_BUILDER_LIST_CHUNK (cursor ,markThings ); 249 250 { 251SLANG_SCOPED_RIFF_BUILDER_DATA_CHUNK (cursor ,markData ); 252 253const char another []= "Another?" ; 254cursor .addData (another ,sizeof (another )); 255 } 256 } 257 } 258 259SLANG_CHECK (cursor .getCurrentChunk ()== nullptr ); 260SLANG_CHECK (riffBuilder .getRootChunk ()!= nullptr ); 261 262 { 263StringBuilder builder ; 264 { 265StringWriter writer (& builder ); 266_dump (riffBuilder .getRootChunk (),& writer ); 267 } 268 269 { 270ComPtr < ISlangBlob > blob ; 271SLANG_CHECK (SLANG_SUCCEEDED (riffBuilder .writeToBlob (blob .writeRef ()))); 272 273auto rootChunk = RIFF ::RootChunk ::getFromBlob (blob ); 274SLANG_CHECK (rootChunk != nullptr ); 275 276// Dump the read contents 277StringBuilder readBuilder ; 278 { 279StringWriter writer (& readBuilder ,0 ); 280_dump (rootChunk ,& writer ); 281 } 282 283// They should be the same 284SLANG_CHECK (readBuilder == builder ); 285 } 286 } 287 } 288 289// Test writing as a stream only allocates a single data block (as long as there is enough 290// space). 291 { 292RIFF ::Builder builder ; 293RIFF ::BuildCursor cursor (builder ); 294 295SLANG_SCOPED_RIFF_BUILDER_LIST_CHUNK (cursor ,markThings ); 296 { 297SLANG_SCOPED_RIFF_BUILDER_DATA_CHUNK (cursor ,markData ); 298 299RefPtr < RandomGenerator > rand = RandomGenerator ::create (0x345234 ); 300 301List < uint8_t > data ; 302_writeRandom (rand ,builder ._getMemoryArena ().getBlockPayloadSize () /2 ,cursor ,data ); 303 304// Should be a single block with same data as the List 305RIFF ::DataChunkBuilder * dataChunk = 306as < RIFF ::DataChunkBuilder > (cursor .getCurrentChunk ()); 307SLANG_ASSERT (dataChunk ); 308 309// It should be a single shard 310SLANG_CHECK (_isSingleShard (dataChunk )); 311 312SLANG_CHECK (_isEqual (dataChunk ,data .getBuffer (),data .getCount ())); 313 } 314 } 315 316// Test writing across multiple data blocks 317 { 318RefPtr < RandomGenerator > rand = RandomGenerator ::create (0x345234 ); 319 320for (Int i = 0 ;i < 100 ;++ i ) 321 { 322RIFF ::Builder builder ; 323RIFF ::BuildCursor cursor (builder ); 324 325const size_t maxSize = rand -> nextInt32InRange ( 3261 , 327int32_t (builder ._getMemoryArena ().getBlockPayloadSize ()* 3 )); 328 329SLANG_SCOPED_RIFF_BUILDER_LIST_CHUNK (cursor ,markThings ); 330 { 331SLANG_SCOPED_RIFF_BUILDER_DATA_CHUNK (cursor ,markData ); 332 333List < uint8_t > data ; 334_writeRandom (rand ,maxSize ,cursor ,data ); 335 336// Should be a single block with same data as the List 337RIFF ::DataChunkBuilder * dataChunk = 338as < RIFF ::DataChunkBuilder > (cursor .getCurrentChunk ()); 339SLANG_CHECK (dataChunk && _isEqual (dataChunk ,data .getBuffer (),data .getCount ())); 340 } 341 } 342 } 343 344#if 0 345 { 346RiffContainer container ; 347 { 348FileStream readStream ("ambient-drop.wav" ,FileMode ::Open ,FileAccess ::Read ,FileShare ::ReadWrite ); 349SLANG_CHECK (SLANG_SUCCEEDED (RiffUtil ::read (& readStream ,container ))); 350RiffUtil ::dump (container .getRoot (),StdWriters ::getOut ()); 351 } 352// Write it 353 { 354 355FileStream writeStream ("check.wav" ,FileMode ::Create ,FileAccess ::Write ,FileShare ::ReadWrite ); 356SLANG_CHECK (SLANG_SUCCEEDED (RiffUtil ::write (container .getRoot (), true,& writeStream ))); 357 } 358 } 359#endif 360}