/* * This file is part of the Aaru Data Preservation Suite. * Copyright (c) 2019-2023 Natalia Portillo. * Copyright © 2018-2019 David Ryskalczyk * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include #include #include #include "library.h" #include "apple_rle.h" AARU_EXPORT int32_t AARU_CALL AARU_apple_rle_decode_buffer(uint8_t* dst_buffer, int32_t dst_size, const uint8_t* src_buffer, int32_t src_size) { static int32_t count = 0; static bool nextA = true; // true if A, false if B static uint8_t repeatedByteA = 0, repeatedByteB = 0; static bool repeatMode = false; // true if we're repeating, false if we're just copying int32_t in_pos = 0, out_pos = 0; while(in_pos <= src_size && out_pos <= dst_size) { if(repeatMode && count > 0) { (count)--; if(nextA) { nextA = false; dst_buffer[out_pos++] = repeatedByteA; continue; } nextA = true; dst_buffer[out_pos++] = repeatedByteB; continue; } if(!repeatMode && count > 0) { count--; dst_buffer[out_pos++] = src_buffer[in_pos++]; continue; } if(in_pos == src_size) break; while(true) { uint8_t b1 = src_buffer[in_pos++]; uint8_t b2 = src_buffer[in_pos++]; int16_t s = (int16_t)((b1 << 8) | b2); if(s == 0 || s >= DART_CHUNK || s <= -DART_CHUNK) continue; if(s < 0) { repeatMode = true; repeatedByteA = src_buffer[in_pos++]; repeatedByteB = src_buffer[in_pos++]; count = (-s * 2) - 1; nextA = false; dst_buffer[out_pos++] = repeatedByteA; break; } repeatMode = false; count = (s * 2) - 1; dst_buffer[out_pos++] = src_buffer[in_pos++]; break; } } return out_pos; }