You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IReader.cpp 10.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #include "ebml/IReader.h"
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <cstring>
  5. #include <iostream>
  6. #if 0
  7. #define _Debug_ _is_in_debug_mode_(m_totalBytes)
  8. static bool _is_in_debug_mode_(uint64_t value)
  9. {
  10. static int i=0;
  11. // bool result=i++>5500000;
  12. bool result=value>29605500;
  13. if (result) std::cout << "Arround " << value << std::endl;
  14. return result;
  15. }
  16. #else
  17. #define _Debug_ false
  18. #endif
  19. // ________________________________________________________________________________________________________________
  20. //
  21. inline bool needsTwoBytesToGetCodedSizeLength(const unsigned char* buffer) { return buffer[0] == 0; }
  22. inline size_t getCodedSizeLength(const unsigned char* buffer)
  23. {
  24. if (buffer[0] >> 7) { return 1; }
  25. if (buffer[0] >> 6) { return 2; }
  26. if (buffer[0] >> 5) { return 3; }
  27. if (buffer[0] >> 4) { return 4; }
  28. if (buffer[0] >> 3) { return 5; }
  29. if (buffer[0] >> 2) { return 6; }
  30. if (buffer[0] >> 1) { return 7; }
  31. if (buffer[0]) { return 8; }
  32. if (buffer[1] >> 7) { return 9; }
  33. return 10;
  34. }
  35. inline uint64_t getValue(unsigned char* buffer)
  36. {
  37. uint64_t result = 0;
  38. const size_t length = getCodedSizeLength(buffer);
  39. size_t ithBit = length;
  40. for (size_t i = 0; i < length; ++i)
  41. {
  42. result = (result << 8) + (buffer[i]);
  43. result &= ~(ithBit > 0 && ithBit <= 8 ? (1 << (8 - ithBit)) : 0);
  44. ithBit -= 8;
  45. }
  46. return result;
  47. }
  48. // ________________________________________________________________________________________________________________
  49. //
  50. namespace EBML {
  51. namespace {
  52. class CReaderNode
  53. {
  54. public:
  55. CReaderNode(const CIdentifier& identifier, CReaderNode* parentNode) : m_ParentNode(parentNode), m_Id(identifier) { }
  56. private:
  57. CReaderNode() = delete;
  58. public:
  59. CReaderNode* m_ParentNode = nullptr;
  60. CIdentifier m_Id;
  61. size_t m_ContentSize = 0;
  62. size_t m_ReadContentSize = 0;
  63. unsigned char* m_Buffer = nullptr;
  64. };
  65. } // namespace
  66. } // namespace EBML
  67. // ________________________________________________________________________________________________________________
  68. //
  69. namespace EBML {
  70. namespace {
  71. class CReader final : public IReader
  72. {
  73. public:
  74. explicit CReader(IReaderCallback& callback) : m_readerCB(callback) { }
  75. ~CReader() override;
  76. bool processData(const void* buffer, const size_t size) override;
  77. CIdentifier getCurrentNodeID() const override;
  78. size_t getCurrentNodeSize() const override;
  79. void release() override;
  80. protected:
  81. enum EStatus
  82. {
  83. FillingIdentifier,
  84. FillingContentSize,
  85. FillingContent,
  86. };
  87. IReaderCallback& m_readerCB;
  88. CReaderNode* m_currentNode = nullptr;
  89. size_t m_pendingSize = 0;
  90. size_t m_nPending = 0;
  91. unsigned char* m_pending = nullptr;
  92. EStatus m_status = FillingIdentifier;
  93. EStatus m_lastStatus = FillingIdentifier;
  94. CIdentifier m_currentID = 0;
  95. size_t m_currentContentSize = 0;
  96. size_t m_totalBytes = 0;
  97. };
  98. } // namespace
  99. // ________________________________________________________________________________________________________________
  100. //
  101. CReader::~CReader()
  102. {
  103. delete [] m_pending;
  104. while (m_currentNode)
  105. {
  106. CReaderNode* parentNode = m_currentNode->m_ParentNode;
  107. delete m_currentNode;
  108. m_currentNode = parentNode;
  109. }
  110. }
  111. bool CReader::processData(const void* buffer, const size_t size)
  112. {
  113. m_totalBytes += size;
  114. if (_Debug_)
  115. {
  116. std::cout << "Received " << size << " byte(s) new buffer :";
  117. for (int i = 0; i < int(size) /* && i<4*/; ++i) { printf("[%02X]", ((unsigned char*)buffer)[i]); }
  118. std::cout << "...\n";
  119. }
  120. if (!buffer || !size) { return true; }
  121. unsigned char* tmpBuffer = (unsigned char*)buffer;
  122. size_t currentSize = size;
  123. bool finished = false;
  124. while (!finished)
  125. {
  126. size_t processedPendingBytes = 0;
  127. size_t processedBytes = 0;
  128. m_lastStatus = m_status;
  129. if (_Debug_ && m_nPending)
  130. {
  131. std::cout << m_nPending << " byte(s) pending : ";
  132. for (int i = 0; i < int(m_nPending); ++i) { printf("[%02X]", m_pending[i]); }
  133. std::cout << "\n";
  134. }
  135. // Processes data
  136. switch (m_status)
  137. {
  138. case FillingIdentifier:
  139. case FillingContentSize:
  140. {
  141. if (needsTwoBytesToGetCodedSizeLength(m_nPending ? m_pending : tmpBuffer))
  142. {
  143. if (m_nPending + currentSize < 2)
  144. {
  145. finished = true;
  146. break;
  147. }
  148. if (m_nPending == 1)
  149. {
  150. // assumes (currentSize != 0) because (m_nPending + currentSize >= 2) and (m_nPending == 1)
  151. m_pending[1] = tmpBuffer[0];
  152. tmpBuffer++;
  153. m_nPending++;
  154. currentSize--;
  155. }
  156. }
  157. const size_t length = getCodedSizeLength(m_nPending ? m_pending : tmpBuffer);
  158. if (length > currentSize + m_nPending) { finished = true; }
  159. else
  160. {
  161. unsigned char* encodedBuffer = new unsigned char[length];
  162. const size_t pendingBytesToCopy = (length > m_nPending ? m_nPending : length);
  163. memcpy(encodedBuffer, m_pending, size_t(pendingBytesToCopy));
  164. memcpy(encodedBuffer + pendingBytesToCopy, tmpBuffer, size_t(length - pendingBytesToCopy));
  165. const uint64_t value = getValue(encodedBuffer);
  166. delete [] encodedBuffer;
  167. processedPendingBytes = pendingBytesToCopy;
  168. processedBytes = length;
  169. switch (m_status)
  170. {
  171. case FillingIdentifier:
  172. {
  173. m_currentID = value;
  174. m_status = FillingContentSize;
  175. if (_Debug_)
  176. {
  177. printf("Found identifier 0x%llX - Changing status to FillingContentSize...\n", static_cast<unsigned long long>(m_currentID));
  178. }
  179. }
  180. break;
  181. case FillingContentSize:
  182. {
  183. m_currentContentSize = value;
  184. if (m_readerCB.isMasterChild(m_currentID))
  185. {
  186. m_status = FillingIdentifier;
  187. if (_Debug_)
  188. {
  189. std::cout << "Found content size " << m_currentContentSize << " of master node - Changing status to FillingIdentifier...\n";
  190. }
  191. }
  192. else
  193. {
  194. m_status = FillingContent;
  195. if (_Debug_)
  196. {
  197. std::cout << "Found content size " << m_currentContentSize <<
  198. " of *non* master node - Changing status to FillingContent...\n";
  199. }
  200. }
  201. }
  202. break;
  203. case FillingContent:
  204. // Should never happen - avoids the warning
  205. break;
  206. }
  207. }
  208. }
  209. break;
  210. case FillingContent:
  211. {
  212. if (m_currentNode->m_ContentSize == 0)
  213. {
  214. m_status = FillingIdentifier;
  215. if (_Debug_)
  216. {
  217. std::cout << "Finished with " << m_currentNode->m_ContentSize << " byte(s) content - Changing status to FillingIdentifier...\n";
  218. }
  219. m_readerCB.processChildData(nullptr, 0);
  220. }
  221. else
  222. {
  223. if (m_currentNode->m_ReadContentSize == 0 && m_currentNode->m_ContentSize <= currentSize)
  224. {
  225. m_status = FillingIdentifier;
  226. processedBytes = m_currentNode->m_ContentSize;
  227. if (_Debug_)
  228. {
  229. std::cout << "Optimized processing of " << m_currentNode->m_ContentSize <<
  230. " byte(s) content - Changing status to FillingIdentifier...\n";
  231. }
  232. m_readerCB.processChildData(tmpBuffer, m_currentNode->m_ContentSize);
  233. }
  234. else
  235. {
  236. if (m_currentNode->m_ContentSize - m_currentNode->m_ReadContentSize > currentSize)
  237. {
  238. memcpy(m_currentNode->m_Buffer + m_currentNode->m_ReadContentSize, tmpBuffer, size_t(currentSize));
  239. processedBytes = currentSize;
  240. finished = true;
  241. }
  242. else
  243. {
  244. memcpy(m_currentNode->m_Buffer + m_currentNode->m_ReadContentSize, tmpBuffer,
  245. size_t(m_currentNode->m_ContentSize - m_currentNode->m_ReadContentSize));
  246. processedBytes = m_currentNode->m_ContentSize - m_currentNode->m_ReadContentSize;
  247. m_status = FillingIdentifier;
  248. if (_Debug_)
  249. {
  250. std::cout << "Finished with " << m_currentNode->m_ContentSize << " byte(s) content - Changing status to FillingIdentifier...\n";
  251. }
  252. m_readerCB.processChildData(m_currentNode->m_Buffer, m_currentNode->m_ContentSize);
  253. }
  254. }
  255. }
  256. }
  257. break;
  258. }
  259. // Updates buffer pointer and size
  260. const size_t processedBytesInBuffer = processedBytes - processedPendingBytes;
  261. tmpBuffer += processedBytesInBuffer;
  262. currentSize -= processedBytesInBuffer;
  263. m_nPending -= processedPendingBytes;
  264. // Updates read size
  265. CReaderNode* node = m_currentNode;
  266. while (node)
  267. {
  268. node->m_ReadContentSize += processedBytes;
  269. node = node->m_ParentNode;
  270. }
  271. // Creates new node when needed
  272. if (m_status != FillingContentSize && m_lastStatus == FillingContentSize)
  273. {
  274. m_currentNode = new CReaderNode(m_currentID, m_currentNode);
  275. m_currentNode->m_ContentSize = m_currentContentSize;
  276. m_currentNode->m_Buffer = new unsigned char[m_currentContentSize];
  277. m_readerCB.openChild(m_currentNode->m_Id);
  278. }
  279. else
  280. {
  281. // Closes finished nodes
  282. while (m_currentNode && (m_currentNode->m_ContentSize == m_currentNode->m_ReadContentSize || m_currentNode->m_ContentSize == 0))
  283. {
  284. m_readerCB.closeChild();
  285. CReaderNode* parent = m_currentNode->m_ParentNode;
  286. delete [] m_currentNode->m_Buffer;
  287. delete m_currentNode;
  288. m_currentNode = parent;
  289. }
  290. }
  291. }
  292. // Updates pending data
  293. if (m_nPending + currentSize > m_pendingSize)
  294. {
  295. unsigned char* pending = new unsigned char[m_nPending + currentSize + 1
  296. ]; // Ugly hack, reserve 1 more byte on pending data so we are sure we can insert this additional pending byte when only one byte is pending and two bytes are needed for decoding identifier and/or buffer size
  297. memcpy(pending, m_pending, m_nPending);
  298. delete [] m_pending;
  299. m_pending = pending;
  300. m_pendingSize = m_nPending + currentSize;
  301. }
  302. memcpy(m_pending + m_nPending, tmpBuffer, currentSize);
  303. m_nPending += currentSize;
  304. if (_Debug_) { std::cout << "\n"; }
  305. return true;
  306. }
  307. CIdentifier CReader::getCurrentNodeID() const { return m_currentNode ? m_currentNode->m_Id : CIdentifier(); }
  308. size_t CReader::getCurrentNodeSize() const { return m_currentNode ? m_currentNode->m_ContentSize : 0; }
  309. void CReader::release() { delete this; }
  310. // ________________________________________________________________________________________________________________
  311. //
  312. EBML_API IReader* createReader(IReaderCallback& callback) { return new CReader(callback); }
  313. } // namespace EBML