aboutsummaryrefslogtreecommitdiff
path: root/Src/nsmkv/SeekTable.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/nsmkv/SeekTable.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/nsmkv/SeekTable.cpp')
-rw-r--r--Src/nsmkv/SeekTable.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/Src/nsmkv/SeekTable.cpp b/Src/nsmkv/SeekTable.cpp
new file mode 100644
index 00000000..78bf118c
--- /dev/null
+++ b/Src/nsmkv/SeekTable.cpp
@@ -0,0 +1,230 @@
+#include "SeekTable.h"
+#include "read.h"
+#include "global_elements.h"
+#include "vint.h"
+#include <stdio.h>
+#include <assert.h>
+
+#ifdef WA_VALIDATE
+extern uint32_t num_seekhead_elements_found;
+extern uint32_t num_seek_elements_found;
+#endif
+
+bool nsmkv::SeekTable::GetEntry(uint64_t id, uint64_t *position)
+{
+ return EnumEntry(0, id, position);
+}
+
+bool nsmkv::SeekTable::EnumEntry(size_t i, uint64_t id, uint64_t *position)
+{
+ SeekMap::iterator found = seekMap.find(id);
+ if (found != seekMap.end())
+ {
+ SeekEntries *entries = found->second;
+ if (entries && entries->size() > i)
+ {
+ *position = entries->at(i).position;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool nsmkv::SeekTable::EnumEntry(size_t i, uint64_t id, SeekEntry **seek_entry)
+{
+ SeekMap::iterator found = seekMap.find(id);
+ if (found != seekMap.end())
+ {
+ SeekEntries *entries = found->second;
+ if (entries && entries->size() > i)
+ {
+ *seek_entry = &entries->at(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void nsmkv::SeekTable::AddEntry(nsmkv::SeekEntry &entry, int flags)
+{
+ // check for duplicates
+ size_t i=0;
+ SeekEntry *seek_entry;
+ while (EnumEntry(i++, entry.id, &seek_entry))
+ {
+ if (flags & ADDENTRY_SINGLE)
+ {
+ if (flags & ADDENTRY_FOUND)
+ seek_entry->position = entry.position;
+ return;
+ }
+
+ if (entry.position == seek_entry->position)
+ {
+ return;
+ }
+ }
+
+ SeekEntries *&entries = seekMap[entry.id];
+ if (!entries)
+ {
+ entries = new SeekEntries;
+ }
+ entries->push_back(entry);
+#ifdef WA_VALIDATE
+ num_seek_elements_found++;
+#endif
+}
+
+void nsmkv::SeekTable::Dump()
+{
+ SeekMap::iterator itr;
+ for (itr=seekMap.begin();itr!=seekMap.end();itr++)
+ {
+ SeekEntries *entries = itr->second;
+ if (entries)
+ {
+ SeekEntries::iterator seekItr;
+ for (seekItr=entries->begin();seekItr!=entries->end();seekItr++)
+ {
+ SeekEntry &entry = *seekItr;
+ printf("Seek Entry -> id=%I64x, position=%I64u\n", entry.id, entry.position);
+ }
+ }
+ }
+}
+
+// returns bytes read. 0 means EOF
+static uint64_t ReadSeek(nsmkv::MKVReader *reader, uint64_t size, nsmkv::SeekTable &seekTable)
+{
+ uint64_t total_bytes_read=0;
+ nsmkv::SeekEntry entry;
+
+ enum
+ {
+ ID_FIELD_PARSED = 0x1,
+ POSITION_FIELD_PARSED = 0x2,
+ };
+ int fields_parsed=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_metaseek_seekid:
+ {
+ uint8_t binary[9] = {0};
+ if (!node.size || node.size > 9)
+ {
+#ifdef WA_VALIDATE
+ printf(" SeekID size invalid, size=%d\n",node.size);
+#endif
+ assert(node.size<9);
+ return 0;
+ }
+
+ size_t bytes_read;
+ reader->Read(binary, (size_t)node.size, &bytes_read);
+ if (bytes_read != (size_t)node.size)
+ return 0;
+#ifdef WA_VALIDATE
+ printf(" SeekID: %I64x\n", vint_read_ptr_len(node.size-1, binary));
+#endif
+ entry.id = vint_read_ptr_len((uint8_t)node.size-1, binary);
+ fields_parsed |= ID_FIELD_PARSED;
+ }
+ break;
+ case mkv_metaseek_seekposition:
+ {
+ uint64_t val;
+ if (read_unsigned(reader, node.size, &val) == 0)
+ return 0;
+#ifdef WA_VALIDATE
+ printf(" SeekPosition: %I64u\n", val);
+#endif
+ entry.position = val;
+ fields_parsed |= POSITION_FIELD_PARSED;
+ }
+ break;
+ default:
+ nsmkv::ReadGlobal(reader, node.id, node.size);
+ }
+ }
+ if (fields_parsed == 0x3)
+ {
+ //entry.state = nsmkv::NOT_READ;
+ seekTable.AddEntry(entry);
+ }
+#ifdef WA_VALIDATE
+ else if (fields_parsed == 0x2)
+ {
+ printf(" Seek only contains SeekPosition\n");
+ } else if (fields_parsed == 0x01)
+ {
+ printf(" Seek element only contains SeekID\n");
+ }
+#endif
+ return total_bytes_read;
+}
+
+
+// returns bytes read. 0 means EOF
+uint64_t nsmkv::ReadSeekHead(nsmkv::MKVReader *reader, uint64_t size, nsmkv::SeekTable &seekTable)
+{
+ uint64_t total_bytes_read=0;
+#ifdef WA_VALIDATE
+ num_seekhead_elements_found++;
+#endif
+
+ 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_metaseek_seek:
+ {
+#ifdef WA_VALIDATE
+ printf(" Seek\n");
+#endif
+ ReadSeek(reader, node.size, seekTable);
+ }
+ break;
+ default:
+ ReadGlobal(reader, node.id, node.size);
+ }
+ }
+ return total_bytes_read;
+}
+