Skip to content

Commit

Permalink
Fix parsing of certain dc6 found in casc (#116)
Browse files Browse the repository at this point in the history
* Fix parsing of certain dc6 found in casc

This is pretty ugly, ignoring Length, please suggest any better way

* Stop reading the whole dc6 frame data into array, but read frames directly from stream

* Simplify

* add assert
  • Loading branch information
DarthGandalf committed Feb 13, 2022
1 parent f00da3a commit 811c452
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 26 deletions.
6 changes: 2 additions & 4 deletions libabyss/include/libabyss/formats/d2/dc6.h
@@ -1,9 +1,9 @@
#ifndef LIBABYSS_DC6_H
#define LIBABYSS_DC6_H

#include <cstdint>
#include "libabyss/streams/inputstream.h"
#include "libabyss/streams/streamreader.h"
#include <cstdint>
#include <vector>

namespace LibAbyss {
Expand All @@ -23,12 +23,10 @@ class DC6 {
uint32_t Unknown = 0;
uint32_t NextBlock = 0;
uint32_t Length = 0;
std::vector<uint8_t> FrameData;
std::vector<uint8_t> IndexData;

private:
void Decode();
static uint8_t GetScanlineType(uint8_t b);
void Decode(StreamReader &sr);
};

Direction() : Frames() {}
Expand Down
57 changes: 35 additions & 22 deletions libabyss/src/formats/d2/dc6.cpp
@@ -1,13 +1,26 @@
#include "libabyss/formats/d2/dc6.h"
#include "libabyss/streams/streamreader.h"
#include <stdexcept>

namespace LibAbyss {
namespace {
const uint8_t EndOfScanline = 0x80;
const uint8_t MaxRunLength = 0x7F;
const uint8_t EndOfLine = 1;
const int RunOfTransparentPixels = 2;
const int RunOfOpaquePixels = 3;
constexpr uint8_t EndOfScanline = 0x80;
constexpr uint8_t MaxRunLength = 0x7F;
enum ByteType {
EndOfLine = 1,
RunOfTransparentPixels,
RunOfOpaquePixels,
};

ByteType GetScanlineType(uint8_t b) {
if (b == EndOfScanline)
return EndOfLine;

if ((b & EndOfScanline) > 0)
return RunOfTransparentPixels;

return RunOfOpaquePixels;
}
} // namespace

DC6::DC6(InputStream &stream) : Termination() {
Expand Down Expand Up @@ -38,6 +51,8 @@ DC6::DC6(InputStream &stream) : Termination() {
stream.clear();
stream.seekg(pointers[num++], std::ios_base::beg);
direction.Frames.emplace_back(sr);
if (stream.eof())
throw std::runtime_error("EOF while decoding DC6.");
}

Directions.push_back(direction);
Expand All @@ -53,25 +68,24 @@ DC6::Direction::Frame::Frame(StreamReader &sr) {
Unknown = sr.ReadUInt32();
NextBlock = sr.ReadUInt32();
Length = sr.ReadUInt32();
FrameData.resize(Length);
sr.ReadBytes(FrameData);
IndexData.resize(Width * Height);

Decode();
Decode(sr);
}
void DC6::Direction::Frame::Decode() {
void DC6::Direction::Frame::Decode(StreamReader &sr) {
uint32_t x = 0;
uint32_t y = Height - 1;
uint32_t endy = 0;
if (Flipped) std::swap(y, endy);
if (Flipped)
std::swap(y, endy);
int dy = Flipped ? 1 : -1;
uint32_t offset = 0;

for (;;) {
if (offset >= Length)
throw std::runtime_error("Data overrun while decoding DC6 frame.");

auto b = FrameData[offset++];
auto b = sr.ReadUInt8();
offset++;

switch (GetScanlineType(b)) {
case EndOfLine:
Expand All @@ -85,31 +99,30 @@ void DC6::Direction::Frame::Decode() {
x += (b & MaxRunLength);
continue;
case RunOfOpaquePixels:
if (b == 0) {
// Some D2R DC6 files have data starting with zeros but going over the Length into the padding
offset--;
continue;
}
for (int i = 0; i < b; i++) {
if (offset >= Length)
throw std::runtime_error("Data overrun while decoding DC6 frame.");

if ((x + (y * Width) + i) >= (Width * Height))
throw std::runtime_error("X/Y position out of bounds while decoding DC6 frame.");

IndexData[x + (y * Width) + i] = FrameData[offset++];
IndexData[x + (y * Width) + i] = sr.ReadUInt8();
offset++;
}
x += b;
continue;
}
}

done:
if (offset != Length)
throw std::runtime_error("Invalid DC6 frame length.");
return;
}
uint8_t DC6::Direction::Frame::GetScanlineType(uint8_t b) {
if (b == EndOfScanline)
return EndOfLine;

if ((b & EndOfScanline) > 0)
return RunOfTransparentPixels;

return RunOfOpaquePixels;
}

} // namespace LibAbyss

0 comments on commit 811c452

Please sign in to comment.