140 count = len(chunk.data) - chunkOfs |
142 count = len(chunk.data) - chunkOfs |
141 ioDelta += self.CHUNK_SIZE - len(chunk.data) |
143 ioDelta += self.CHUNK_SIZE - len(chunk.data) |
142 else: |
144 else: |
143 count = maxSize |
145 count = maxSize |
144 if count > 0: |
146 if count > 0: |
145 buffer += chunk.data[chunkOfs:chunkOfs + count] |
147 buffer += chunk.data[chunkOfs : chunkOfs + count] |
146 maxSize -= count |
148 maxSize -= count |
147 pos += count |
149 pos += count |
148 if highlighted is not None: |
150 if highlighted is not None: |
149 highlighted += chunk.dataChanged[ |
151 highlighted += chunk.dataChanged[ |
150 chunkOfs:chunkOfs + count] |
152 chunkOfs : chunkOfs + count |
151 |
153 ] |
|
154 |
152 if maxSize > 0 and pos < chunk.absPos: |
155 if maxSize > 0 and pos < chunk.absPos: |
153 # In this section, we read data from the original source. This |
156 # In this section, we read data from the original source. This |
154 # will only happen, when no copied data is available. |
157 # will only happen, when no copied data is available. |
155 if chunk.absPos - pos > maxSize: |
158 if chunk.absPos - pos > maxSize: |
156 byteCount = maxSize |
159 byteCount = maxSize |
157 else: |
160 else: |
158 byteCount = chunk.absPos - pos |
161 byteCount = chunk.absPos - pos |
159 |
162 |
160 maxSize -= byteCount |
163 maxSize -= byteCount |
161 self.__ioDevice.seek(pos + ioDelta) |
164 self.__ioDevice.seek(pos + ioDelta) |
162 readBuffer = bytearray(self.__ioDevice.read(byteCount)) |
165 readBuffer = bytearray(self.__ioDevice.read(byteCount)) |
163 buffer += readBuffer |
166 buffer += readBuffer |
164 if highlighted is not None: |
167 if highlighted is not None: |
165 highlighted += bytearray(len(readBuffer)) |
168 highlighted += bytearray(len(readBuffer)) |
166 pos += len(readBuffer) |
169 pos += len(readBuffer) |
167 |
170 |
168 self.__ioDevice.close() |
171 self.__ioDevice.close() |
169 return buffer |
172 return buffer |
170 |
173 |
171 def write(self, ioDevice, pos=0, count=-1): |
174 def write(self, ioDevice, pos=0, count=-1): |
172 """ |
175 """ |
173 Public method to write data to an io device. |
176 Public method to write data to an io device. |
174 |
177 |
175 @param ioDevice io device to write the data to |
178 @param ioDevice io device to write the data to |
176 @type QIODevice |
179 @type QIODevice |
177 @param pos position to write bytes from |
180 @param pos position to write bytes from |
178 @type int |
181 @type int |
179 @param count amount of bytes to write |
182 @param count amount of bytes to write |
212 # position is out of range, do nothing |
215 # position is out of range, do nothing |
213 return |
216 return |
214 chunkIdx = self.__getChunkIndex(pos) |
217 chunkIdx = self.__getChunkIndex(pos) |
215 posInChunk = pos - self.__chunks[chunkIdx].absPos |
218 posInChunk = pos - self.__chunks[chunkIdx].absPos |
216 self.__chunks[chunkIdx].dataChanged[posInChunk] = int(dataChanged) |
219 self.__chunks[chunkIdx].dataChanged[posInChunk] = int(dataChanged) |
217 |
220 |
218 def dataChanged(self, pos): |
221 def dataChanged(self, pos): |
219 """ |
222 """ |
220 Public method to test, if some data was changed. |
223 Public method to test, if some data was changed. |
221 |
224 |
222 @param pos byte position to check |
225 @param pos byte position to check |
223 @type int |
226 @type int |
224 @return flag indicating the changed state |
227 @return flag indicating the changed state |
225 @rtype bool |
228 @rtype bool |
226 """ |
229 """ |
227 highlighted = bytearray() |
230 highlighted = bytearray() |
228 self.data(pos, 1, highlighted) |
231 self.data(pos, 1, highlighted) |
229 return highlighted and bool(highlighted[0]) |
232 return highlighted and bool(highlighted[0]) |
230 |
233 |
231 def indexOf(self, byteArray, start): |
234 def indexOf(self, byteArray, start): |
232 """ |
235 """ |
233 Public method to search the first occurrence of some data. |
236 Public method to search the first occurrence of some data. |
234 |
237 |
235 @param byteArray data to search for |
238 @param byteArray data to search for |
236 @type bytearray |
239 @type bytearray |
237 @param start position to start the search at |
240 @param start position to start the search at |
238 @type int |
241 @type int |
239 @return position the data was found at or -1 if nothing could be found |
242 @return position the data was found at or -1 if nothing could be found |
240 @rtype int |
243 @rtype int |
241 """ |
244 """ |
242 ba = bytearray(byteArray) |
245 ba = bytearray(byteArray) |
243 |
246 |
244 result = -1 |
247 result = -1 |
245 pos = start |
248 pos = start |
246 while pos < self.__size: |
249 while pos < self.__size: |
247 buffer = self.data(pos, self.BUFFER_SIZE + len(ba) - 1) |
250 buffer = self.data(pos, self.BUFFER_SIZE + len(ba) - 1) |
248 findPos = buffer.find(ba) |
251 findPos = buffer.find(ba) |
249 if findPos >= 0: |
252 if findPos >= 0: |
250 result = pos + findPos |
253 result = pos + findPos |
251 break |
254 break |
252 |
255 |
253 # increment loop variable |
256 # increment loop variable |
254 pos += self.BUFFER_SIZE |
257 pos += self.BUFFER_SIZE |
255 |
258 |
256 return result |
259 return result |
257 |
260 |
258 def lastIndexOf(self, byteArray, start): |
261 def lastIndexOf(self, byteArray, start): |
259 """ |
262 """ |
260 Public method to search the last occurrence of some data. |
263 Public method to search the last occurrence of some data. |
261 |
264 |
262 @param byteArray data to search for |
265 @param byteArray data to search for |
263 @type bytearray |
266 @type bytearray |
264 @param start position to start the search at |
267 @param start position to start the search at |
265 @type int |
268 @type int |
266 @return position the data was found at or -1 if nothing could be found |
269 @return position the data was found at or -1 if nothing could be found |
267 @rtype int |
270 @rtype int |
268 """ |
271 """ |
269 ba = bytearray(byteArray) |
272 ba = bytearray(byteArray) |
270 |
273 |
271 result = -1 |
274 result = -1 |
272 pos = start |
275 pos = start |
273 while pos > 0 and result < 0: |
276 while pos > 0 and result < 0: |
274 sPos = pos - self.BUFFER_SIZE - len(ba) + 1 |
277 sPos = pos - self.BUFFER_SIZE - len(ba) + 1 |
275 if sPos < 0: |
278 if sPos < 0: |
276 sPos = 0 |
279 sPos = 0 |
277 |
280 |
278 buffer = self.data(sPos, pos - sPos) |
281 buffer = self.data(sPos, pos - sPos) |
279 findPos = buffer.rfind(ba) |
282 findPos = buffer.rfind(ba) |
280 if findPos >= 0: |
283 if findPos >= 0: |
281 result = sPos + findPos |
284 result = sPos + findPos |
282 break |
285 break |
283 |
286 |
284 # increment loop variable |
287 # increment loop variable |
285 pos -= self.BUFFER_SIZE |
288 pos -= self.BUFFER_SIZE |
286 |
289 |
287 return result |
290 return result |
288 |
291 |
289 def insert(self, pos, data): |
292 def insert(self, pos, data): |
290 """ |
293 """ |
291 Public method to insert a byte. |
294 Public method to insert a byte. |
292 |
295 |
293 @param pos position to insert at |
296 @param pos position to insert at |
294 @type int |
297 @type int |
295 @param data byte to insert |
298 @param data byte to insert |
296 @type int (range 0 to 255) |
299 @type int (range 0 to 255) |
297 @return flag indicating success |
300 @return flag indicating success |
298 @rtype bool |
301 @rtype bool |
299 """ |
302 """ |
300 if pos < 0 or pos > self.__size: |
303 if pos < 0 or pos > self.__size: |
301 # position is out of range, do nothing |
304 # position is out of range, do nothing |
302 return False |
305 return False |
303 |
306 |
304 chunkIdx = ( |
307 chunkIdx = ( |
305 self.__getChunkIndex(pos - 1) |
308 self.__getChunkIndex(pos - 1) |
306 if pos == self.__size else |
309 if pos == self.__size |
307 self.__getChunkIndex(pos) |
310 else self.__getChunkIndex(pos) |
308 ) |
311 ) |
309 chunk = self.__chunks[chunkIdx] |
312 chunk = self.__chunks[chunkIdx] |
310 posInChunk = pos - chunk.absPos |
313 posInChunk = pos - chunk.absPos |
311 chunk.data.insert(posInChunk, data) |
314 chunk.data.insert(posInChunk, data) |
312 chunk.dataChanged.insert(posInChunk, 1) |
315 chunk.dataChanged.insert(posInChunk, 1) |
313 for idx in range(chunkIdx + 1, len(self.__chunks)): |
316 for idx in range(chunkIdx + 1, len(self.__chunks)): |
314 self.__chunks[idx].absPos += 1 |
317 self.__chunks[idx].absPos += 1 |
315 self.__size += 1 |
318 self.__size += 1 |
316 self.__pos = pos |
319 self.__pos = pos |
317 return True |
320 return True |
318 |
321 |
319 def overwrite(self, pos, data): |
322 def overwrite(self, pos, data): |
320 """ |
323 """ |
321 Public method to overwrite a byte. |
324 Public method to overwrite a byte. |
322 |
325 |
323 @param pos position to overwrite |
326 @param pos position to overwrite |
324 @type int |
327 @type int |
325 @param data byte to overwrite with |
328 @param data byte to overwrite with |
326 @type int (range 0 to 255) |
329 @type int (range 0 to 255) |
327 @return flag indicating success |
330 @return flag indicating success |
328 @rtype bool |
331 @rtype bool |
329 """ |
332 """ |
330 if pos < 0 or pos >= self.__size: |
333 if pos < 0 or pos >= self.__size: |
331 # position is out of range, do nothing |
334 # position is out of range, do nothing |
332 return False |
335 return False |
333 |
336 |
334 chunkIdx = self.__getChunkIndex(pos) |
337 chunkIdx = self.__getChunkIndex(pos) |
335 chunk = self.__chunks[chunkIdx] |
338 chunk = self.__chunks[chunkIdx] |
336 posInChunk = pos - chunk.absPos |
339 posInChunk = pos - chunk.absPos |
337 chunk.data[posInChunk] = data |
340 chunk.data[posInChunk] = data |
338 chunk.dataChanged[posInChunk] = 1 |
341 chunk.dataChanged[posInChunk] = 1 |
339 self.__pos = pos |
342 self.__pos = pos |
340 return True |
343 return True |
341 |
344 |
342 def removeAt(self, pos): |
345 def removeAt(self, pos): |
343 """ |
346 """ |
344 Public method to remove a byte. |
347 Public method to remove a byte. |
345 |
348 |
346 @param pos position to remove |
349 @param pos position to remove |
347 @type int |
350 @type int |
348 @return flag indicating success |
351 @return flag indicating success |
349 @rtype bool |
352 @rtype bool |
350 """ |
353 """ |
351 if pos < 0 or pos >= self.__size: |
354 if pos < 0 or pos >= self.__size: |
352 # position is out of range, do nothing |
355 # position is out of range, do nothing |
353 return False |
356 return False |
354 |
357 |
355 chunkIdx = self.__getChunkIndex(pos) |
358 chunkIdx = self.__getChunkIndex(pos) |
356 chunk = self.__chunks[chunkIdx] |
359 chunk = self.__chunks[chunkIdx] |
357 posInChunk = pos - chunk.absPos |
360 posInChunk = pos - chunk.absPos |
358 chunk.data.pop(posInChunk) |
361 chunk.data.pop(posInChunk) |
359 chunk.dataChanged.pop(posInChunk) |
362 chunk.dataChanged.pop(posInChunk) |
360 for idx in range(chunkIdx + 1, len(self.__chunks)): |
363 for idx in range(chunkIdx + 1, len(self.__chunks)): |
361 self.__chunks[idx].absPos -= 1 |
364 self.__chunks[idx].absPos -= 1 |
362 self.__size -= 1 |
365 self.__size -= 1 |
363 self.__pos = pos |
366 self.__pos = pos |
364 return True |
367 return True |
365 |
368 |
366 def __getitem__(self, pos): |
369 def __getitem__(self, pos): |
367 """ |
370 """ |
368 Special method to get a byte at a position. |
371 Special method to get a byte at a position. |
369 |
372 |
370 Note: This realizes the [] get operator. |
373 Note: This realizes the [] get operator. |
371 |
374 |
372 @param pos position of byte to get |
375 @param pos position of byte to get |
373 @type int |
376 @type int |
374 @return requested byte |
377 @return requested byte |
375 @rtype int (range 0 to 255) |
378 @rtype int (range 0 to 255) |
376 """ |
379 """ |
377 if pos >= self.__size: |
380 if pos >= self.__size: |
378 return 0 |
381 return 0 |
379 ## raise IndexError |
382 ## raise IndexError |
380 |
383 |
381 return self.data(pos, 1)[0] |
384 return self.data(pos, 1)[0] |
382 |
385 |
383 def pos(self): |
386 def pos(self): |
384 """ |
387 """ |
385 Public method to get the current position. |
388 Public method to get the current position. |
386 |
389 |
387 @return current position |
390 @return current position |
388 @rtype int |
391 @rtype int |
389 """ |
392 """ |
390 return self.__pos |
393 return self.__pos |
391 |
394 |
392 def size(self): |
395 def size(self): |
393 """ |
396 """ |
394 Public method to get the current data size. |
397 Public method to get the current data size. |
395 |
398 |
396 @return current data size |
399 @return current data size |
397 @rtype int |
400 @rtype int |
398 """ |
401 """ |
399 return self.__size |
402 return self.__size |
400 |
403 |
401 def __getChunkIndex(self, absPos): |
404 def __getChunkIndex(self, absPos): |
402 """ |
405 """ |
403 Private method to get the chunk index for a position. |
406 Private method to get the chunk index for a position. |
404 |
407 |
405 This method checks, if there is already a copied chunk available. If |
408 This method checks, if there is already a copied chunk available. If |
406 there is one, it returns its index. If there is no copied chunk |
409 there is one, it returns its index. If there is no copied chunk |
407 available, original data will be copied into a new chunk. |
410 available, original data will be copied into a new chunk. |
408 |
411 |
409 @param absPos absolute position of the data. |
412 @param absPos absolute position of the data. |
410 @type int |
413 @type int |
411 @return index of the chunk containing the position |
414 @return index of the chunk containing the position |
412 @rtype int |
415 @rtype int |
413 """ |
416 """ |
414 foundIdx = -1 |
417 foundIdx = -1 |
415 insertIdx = 0 |
418 insertIdx = 0 |
416 ioDelta = 0 |
419 ioDelta = 0 |
417 |
420 |
418 for idx in range(len(self.__chunks)): |
421 for idx in range(len(self.__chunks)): |
419 chunk = self.__chunks[idx] |
422 chunk = self.__chunks[idx] |
420 if ( |
423 if absPos >= chunk.absPos and absPos < (chunk.absPos + len(chunk.data)): |
421 absPos >= chunk.absPos and |
|
422 absPos < (chunk.absPos + len(chunk.data)) |
|
423 ): |
|
424 foundIdx = idx |
424 foundIdx = idx |
425 break |
425 break |
426 |
426 |
427 if absPos < chunk.absPos: |
427 if absPos < chunk.absPos: |
428 insertIdx = idx |
428 insertIdx = idx |
429 break |
429 break |
430 |
430 |
431 ioDelta += len(chunk.data) - self.CHUNK_SIZE |
431 ioDelta += len(chunk.data) - self.CHUNK_SIZE |
432 insertIdx = idx + 1 |
432 insertIdx = idx + 1 |
433 |
433 |
434 if foundIdx == -1: |
434 if foundIdx == -1: |
435 newChunk = HexEditChunk() |
435 newChunk = HexEditChunk() |
436 readAbsPos = absPos - ioDelta |
436 readAbsPos = absPos - ioDelta |
437 readPos = readAbsPos & self.READ_CHUNK_MASK |
437 readPos = readAbsPos & self.READ_CHUNK_MASK |
438 self.__ioDevice.open(QIODevice.OpenModeFlag.ReadOnly) |
438 self.__ioDevice.open(QIODevice.OpenModeFlag.ReadOnly) |