diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/nsmkv/Cluster.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/nsmkv/Cluster.cpp')
-rw-r--r-- | Src/nsmkv/Cluster.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/Src/nsmkv/Cluster.cpp b/Src/nsmkv/Cluster.cpp new file mode 100644 index 00000000..94949138 --- /dev/null +++ b/Src/nsmkv/Cluster.cpp @@ -0,0 +1,213 @@ +#include "Cluster.h" +#include "read.h" +#include "global_elements.h" +#include <winsock.h> + +// returns bytes read. 0 means EOF +uint64_t nsmkv::ReadBlockGroup(nsmkv::MKVReader *reader, uint64_t size, nsmkv::Block &block, uint64_t *allowed_track_numbers, size_t num_allowed_track_numbers) +{ + uint64_t total_bytes_read=0; + while (size) + { + uint64_t ebml_start_position = reader->Tell(); // need this for recording the block binary start position + ebml_node node; + uint64_t bytes_read = read_ebml_node(reader, &node); + + if (bytes_read == 0) + return 0; + + // benski> checking bytes_read and node.size separately prevents possible integer overflow attack + if (bytes_read > size) + return 0; + total_bytes_read+=bytes_read; + size-=bytes_read; + + if (node.size > size) + return 0; + total_bytes_read+=node.size; + size-=node.size; + + switch(node.id) + { + case mkv_blockgroup_referenceblock: + { + int64_t val; + if (read_signed(reader, node.size, &val) == 0) + return 0; + +#ifdef WA_VALIDATE + printf(" Reference Block: %I64d\n", val); +#endif + block.reference_block = val; + } + break; + case mkv_blockgroup_block: + { +#ifdef WA_VALIDATE + printf(" Block: binary size %I64u\n", node.size); +#endif + if (ReadBlockBinary(reader, node.size, block.binary, allowed_track_numbers, num_allowed_track_numbers) == 0) + return 0; + } + break; + case mkv_blockgroup_blockduration: + { + uint64_t val; + if (read_unsigned(reader, node.size, &val) == 0) + return 0; + +#ifdef WA_VALIDATE + printf(" Block Duration: %I64u\n", val); +#endif + block.block_duration = val; + } + break; + default: + nsmkv::ReadGlobal(reader, node.id, node.size); + } + } + return total_bytes_read; +} + +// returns bytes read. 0 means EOF +uint64_t nsmkv::ReadCluster(nsmkv::MKVReader *reader, uint64_t size, nsmkv::Cluster &cluster) +{ + uint64_t total_bytes_read=0; + while (size) + { + ebml_node node; + uint64_t bytes_read = read_ebml_node(reader, &node); + + if (bytes_read == 0) + return 0; + + // benski> checking bytes_read and node.size separately prevents possible integer overflow attack + if (bytes_read > size) + return 0; + total_bytes_read+=bytes_read; + size-=bytes_read; + + if (node.size > size) + return 0; + total_bytes_read+=node.size; + size-=node.size; + + switch(node.id) + { + case mkv_cluster_timecode: + { + uint64_t val; + if (read_unsigned(reader, node.size, &val) == 0) + return 0; + +#ifdef WA_VALIDATE + printf(" Time Code: %I64u\n", val); + cluster.time_code_found = true; +#endif + cluster.time_code = val; + } + break; + case mkv_cluster_blockgroup: + { +#ifdef WA_VALIDATE + printf(" Block Group\n"); +#endif + Block block; + if (ReadBlockGroup(reader, node.size, block, 0, 0) == 0) + return 0; + } + break; + case mkv_cluster_simpleblock: + { +#ifdef WA_VALIDATE + printf(" Simple Block, size: %I64u\n", node.size); +#endif + BlockBinary bbinary; + if (ReadBlockBinary(reader, node.size, bbinary, 0, 0) == 0) + return 0; +// fseek64(f, node.size, SEEK_CUR); + } + break; + default: + ReadGlobal(reader, node.id, node.size); + } + } + return total_bytes_read; +} + + +uint64_t nsmkv::ReadBlockBinary(nsmkv::MKVReader *reader, uint64_t size, nsmkv::BlockBinary &binary, uint64_t *allowed_track_numbers, size_t num_allowed_track_numbers) +{ + uint64_t orig_size = size; + size_t bytes_read = (size_t)read_vint(reader, &binary.track_number); + if (!bytes_read) + return 0; + size-=bytes_read; + bool allowed_track=false; + if (num_allowed_track_numbers == (size_t)-1) + { + allowed_track=true; + } + else + { + for (size_t i=0;i!=num_allowed_track_numbers;i++) + { + if (binary.track_number == allowed_track_numbers[i]) + { + allowed_track=true; + break; + } + } + } +#ifdef WA_VALIDATE + // if we are validating the file, force all tracks to go thru + allowed_track = true; +#endif + if (allowed_track && size >= 3) + { + uint16_t time_code_endian; + size_t bytes_read; + reader->Read(&time_code_endian, sizeof(uint16_t), &bytes_read); + if (bytes_read != sizeof(uint16_t)) + return 0; + binary.time_code = htons(time_code_endian); + size-=sizeof(uint16_t); + + uint8_t flags; + reader->Read(&flags, 1, &bytes_read); + if (bytes_read != 1) + return 0; + + binary.flags = flags; + size -= sizeof(uint8_t); + + binary.data_size = (size_t)size; +#ifndef WA_VALIDATE + binary.data = malloc((size_t)size); + if (!binary.data) + return 0; + reader->Read(binary.data, (size_t)size, &bytes_read); + if (bytes_read != size) + { + free(binary.data); + return 0; + } +#else + printf(" track number = %I64u\n",binary.track_number); + printf(" timecode = %u\n",binary.time_code); + printf(" flags = %u\n",binary.flags); + printf(" data_size = %I64u\n",size); + // if we are validating the nmk file we don't need to + // actually read the data, just skip past it + //fseek(reader, size, SEEK_CUR); +#endif + return orig_size; + } + else + { + reader->Skip(size); + return orig_size; + } + return 0; +} + |