1 /*
2    mkvmerge -- utility for splicing together matroska files
3    from component media subtypes
4 
5    Distributed under the GPL v2
6    see the file COPYING for details
7    or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8 
9    class definition for a memory slice cursor
10 
11    Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13 
14 #pragma once
15 
16 #include "common/common_pch.h"
17 
18 namespace mtx::mem {
19 
20 class slice_cursor_c {
21 protected:
22   std::size_t m_pos{}, m_pos_in_slice{}, m_size{}, m_current_slice_num{}, m_current_slice_size{};
23   unsigned char *m_current_slice_buffer{};
24   std::vector<memory_cptr> m_slices;
25 
26 public:
slice_cursor_c()27   slice_cursor_c()
28   {
29   }
30 
~slice_cursor_c()31   ~slice_cursor_c() {
32   }
33 
34   slice_cursor_c(slice_cursor_c const &) = delete;
35 
init_slice_variables()36   void init_slice_variables() {
37     if (m_current_slice_num < m_slices.size()) {
38       auto &slice            = *m_slices[m_current_slice_num];
39       m_current_slice_buffer = slice.get_buffer();
40       m_current_slice_size   = slice.get_size();
41     } else {
42       m_current_slice_buffer = nullptr;
43       m_current_slice_size   = 0;
44     }
45   }
46 
add_slice(memory_cptr const & slice)47   void add_slice(memory_cptr const &slice) {
48     if (slice->get_size() == 0)
49       return;
50 
51     m_slices.emplace_back(slice);
52     m_size += slice->get_size();
53 
54     if (!m_current_slice_buffer)
55       init_slice_variables();
56   }
57 
add_slice(unsigned char * buffer,std::size_t size)58   void add_slice(unsigned char *buffer, std::size_t size) {
59     if (0 == size)
60       return;
61 
62     add_slice(memory_c::borrow(buffer, size));
63   }
64 
get_char()65   inline unsigned char get_char() {
66     assert(m_current_slice_buffer && (m_pos < m_size));
67 
68     auto c = m_current_slice_buffer[m_pos_in_slice];
69 
70     ++m_pos_in_slice;
71     ++m_pos;
72 
73     if (m_pos_in_slice < m_current_slice_size)
74       return c;
75 
76     ++m_current_slice_num;
77     m_pos_in_slice = 0;
78 
79     init_slice_variables();
80 
81     return c;
82   }
83 
char_available()84   inline bool char_available() {
85     return m_pos < m_size;
86   }
87 
get_remaining_size()88   inline std::size_t get_remaining_size() {
89     return m_size - m_pos;
90   }
91 
get_size()92   inline std::size_t get_size() {
93     return m_size;
94   }
95 
get_position()96   inline std::size_t get_position() {
97     return m_pos;
98   }
99 
100   void reset(bool clear_slices = false) {
101     if (clear_slices) {
102       m_slices.clear();
103       m_size = 0;
104     }
105 
106     m_pos               = 0;
107     m_pos_in_slice      = 0;
108     m_current_slice_num = 0;
109 
110     init_slice_variables();
111   }
112 
copy(unsigned char * dest,std::size_t start,std::size_t size)113   void copy(unsigned char *dest, std::size_t start, std::size_t size) {
114     assert((start + size) <= m_size);
115 
116     auto curr   = m_slices.begin();
117     auto offset = 0u;
118 
119     while (start > ((*curr)->get_size() + offset)) {
120       offset += (*curr)->get_size();
121       ++curr;
122       assert(m_slices.end() != curr);
123     }
124     offset = start - offset;
125 
126     while (0 < size) {
127       auto num_bytes = (*curr)->get_size() - offset;
128       if (num_bytes > size)
129         num_bytes = size;
130 
131       std::memcpy(dest, (*curr)->get_buffer() + offset, num_bytes);
132 
133       size   -= num_bytes;
134       dest   += num_bytes;
135       offset  = 0;
136       ++curr;
137     }
138   }
139 };
140 
141 }
142