void* UniformAligner::getElement(size_t index) {
	size_t offset = alignSize(_headerSize, _requiredAlignment) + alignSize(_dataSize, _requiredAlignment) * index;

	Assertion(offset < _buffer.size(), "Invalid index specified!");

	return reinterpret_cast<void*>(_buffer.data() + offset);
}
size_t UniformAligner::getOffset(size_t index) {
	size_t offset = alignSize(_headerSize, _requiredAlignment) + alignSize(_dataSize, _requiredAlignment) * index;

	Assertion(offset < _buffer.size(), "Invalid index specified!");

	return offset;
}
void UniformAligner::resize(size_t num_elements) {
	size_t final_size =
		alignSize(_headerSize, _requiredAlignment) + alignSize(_dataSize, _requiredAlignment) * num_elements;

	_buffer.resize(final_size);
	_numElements = num_elements;
}
void* UniformAligner::nextElement(void* currentEl) {
	uint8_t* current = reinterpret_cast<uint8_t*>(currentEl);

	current += alignSize(_dataSize, _requiredAlignment);

	return reinterpret_cast<void*>(current);
}
예제 #5
0
파일: canny.cpp 프로젝트: cyberCBM/DetectO
    parallelCanny(const Mat &_dx, const Mat &_dy, Mat &_map, std::deque<uchar*> &borderPeaksParallel,
                  int _low, int _high, bool _L2gradient) :
        src(_dx), src2(_dy), map(_map), _borderPeaksParallel(borderPeaksParallel),
        low(_low), high(_high), aperture_size(0), L2gradient(_L2gradient)
    {
#if CV_SIMD128
        haveSIMD = hasSIMD128();
        if(haveSIMD)
            _map.create(src.rows + 2, (int)alignSize((size_t)(src.cols + CV_MALLOC_SIMD128 + 1), CV_MALLOC_SIMD128), CV_8UC1);
        else
#endif
            _map.create(src.rows + 2, src.cols + 2,  CV_8UC1);
        map = _map;
        map.row(0).setTo(1);
        map.row(src.rows + 1).setTo(1);
        mapstep = map.cols;
        needGradient = false;
        cn = src.channels();
    }
예제 #6
0
template<class CastOp, class VecOp> void
pyrUp_( const Mat& _src, Mat& _dst, int)
{
    const int PU_SZ = 3;
    typedef typename CastOp::type1 WT;
    typedef typename CastOp::rtype T;

    Size ssize = _src.size(), dsize = _dst.size();
    int cn = _src.channels();
    int bufstep = (int)alignSize((dsize.width+1)*cn, 16);
    AutoBuffer<WT> _buf(bufstep*PU_SZ + 16);
    WT* buf = alignPtr((WT*)_buf, 16);
    AutoBuffer<int> _dtab(ssize.width*cn);
    int* dtab = _dtab;
    WT* rows[PU_SZ];
    CastOp castOp;
    VecOp vecOp;

    CV_Assert( std::abs(dsize.width - ssize.width*2) == dsize.width % 2 &&
               std::abs(dsize.height - ssize.height*2) == dsize.height % 2);
    int k, x, sy0 = -PU_SZ/2, sy = sy0;

    ssize.width *= cn;
    dsize.width *= cn;

    for( x = 0; x < ssize.width; x++ )
        dtab[x] = (x/cn)*2*cn + x % cn;

    for( int y = 0; y < ssize.height; y++ )
    {
        T* dst0 = (T*)(_dst.data + _dst.step*y*2);
        T* dst1 = (T*)(_dst.data + _dst.step*(y*2+1));
        WT *row0, *row1, *row2;

        if( y*2+1 >= dsize.height )
            dst1 = dst0;

        // fill the ring buffer (horizontal convolution and decimation)
        for( ; sy <= y + 1; sy++ )
        {
            WT* row = buf + ((sy - sy0) % PU_SZ)*bufstep;
            int _sy = borderInterpolate(sy*2, dsize.height, BORDER_REFLECT_101)/2;
            const T* src = (const T*)(_src.data + _src.step*_sy);

            if( ssize.width == cn )
            {
                for( x = 0; x < cn; x++ )
                    row[x] = row[x + cn] = src[x]*8;
                continue;
            }

            for( x = 0; x < cn; x++ )
            {
                int dx = dtab[x];
                WT t0 = src[x]*6 + src[x + cn]*2;
                WT t1 = (src[x] + src[x + cn])*4;
                row[dx] = t0; row[dx + cn] = t1;
                dx = dtab[ssize.width - cn + x];
                int sx = ssize.width - cn + x;
                t0 = src[sx - cn] + src[sx]*7;
                t1 = src[sx]*8;
                row[dx] = t0; row[dx + cn] = t1;
            }

            for( x = cn; x < ssize.width - cn; x++ )
            {
                int dx = dtab[x];
                WT t0 = src[x-cn] + src[x]*6 + src[x+cn];
                WT t1 = (src[x] + src[x+cn])*4;
                row[dx] = t0;
                row[dx+cn] = t1;
            }
        }

        // do vertical convolution and decimation and write the result to the destination image
        for( k = 0; k < PU_SZ; k++ )
            rows[k] = buf + ((y - PU_SZ/2 + k - sy0) % PU_SZ)*bufstep;
        row0 = rows[0]; row1 = rows[1]; row2 = rows[2];

        x = vecOp(rows, dst0, (int)_dst.step, dsize.width);
        for( ; x < dsize.width; x++ )
        {
            T t1 = castOp((row1[x] + row2[x])*4);
            T t0 = castOp(row0[x] + row1[x]*6 + row2[x]);
            dst1[x] = t1; dst0[x] = t0;
        }
    }
}
예제 #7
0
template<class CastOp, class VecOp> void
pyrDown_( const Mat& _src, Mat& _dst, int borderType )
{
    const int PD_SZ = 5;
    typedef typename CastOp::type1 WT;
    typedef typename CastOp::rtype T;

    CV_Assert( !_src.empty() );
    Size ssize = _src.size(), dsize = _dst.size();
    int cn = _src.channels();
    int bufstep = (int)alignSize(dsize.width*cn, 16);
    AutoBuffer<WT> _buf(bufstep*PD_SZ + 16);
    WT* buf = alignPtr((WT*)_buf, 16);
    int tabL[CV_CN_MAX*(PD_SZ+2)], tabR[CV_CN_MAX*(PD_SZ+2)];
    AutoBuffer<int> _tabM(dsize.width*cn);
    int* tabM = _tabM;
    WT* rows[PD_SZ];
    CastOp castOp;
    VecOp vecOp;

    CV_Assert( ssize.width > 0 && ssize.height > 0 &&
               std::abs(dsize.width*2 - ssize.width) <= 2 &&
               std::abs(dsize.height*2 - ssize.height) <= 2 );
    int k, x, sy0 = -PD_SZ/2, sy = sy0, width0 = std::min((ssize.width-PD_SZ/2-1)/2 + 1, dsize.width);

    for( x = 0; x <= PD_SZ+1; x++ )
    {
        int sx0 = borderInterpolate(x - PD_SZ/2, ssize.width, borderType)*cn;
        int sx1 = borderInterpolate(x + width0*2 - PD_SZ/2, ssize.width, borderType)*cn;
        for( k = 0; k < cn; k++ )
        {
            tabL[x*cn + k] = sx0 + k;
            tabR[x*cn + k] = sx1 + k;
        }
    }

    ssize.width *= cn;
    dsize.width *= cn;
    width0 *= cn;

    for( x = 0; x < dsize.width; x++ )
        tabM[x] = (x/cn)*2*cn + x % cn;

    for( int y = 0; y < dsize.height; y++ )
    {
        T* dst = (T*)(_dst.data + _dst.step*y);
        WT *row0, *row1, *row2, *row3, *row4;

        // fill the ring buffer (horizontal convolution and decimation)
        for( ; sy <= y*2 + 2; sy++ )
        {
            WT* row = buf + ((sy - sy0) % PD_SZ)*bufstep;
            int _sy = borderInterpolate(sy, ssize.height, borderType);
            const T* src = (const T*)(_src.data + _src.step*_sy);
            int limit = cn;
            const int* tab = tabL;

            for( x = 0;;)
            {
                for( ; x < limit; x++ )
                {
                    row[x] = src[tab[x+cn*2]]*6 + (src[tab[x+cn]] + src[tab[x+cn*3]])*4 +
                        src[tab[x]] + src[tab[x+cn*4]];
                }

                if( x == dsize.width )
                    break;

                if( cn == 1 )
                {
                    for( ; x < width0; x++ )
                        row[x] = src[x*2]*6 + (src[x*2 - 1] + src[x*2 + 1])*4 +
                            src[x*2 - 2] + src[x*2 + 2];
                }
                else if( cn == 3 )
                {
                    for( ; x < width0; x += 3 )
                    {
                        const T* s = src + x*2;
                        WT t0 = s[0]*6 + (s[-3] + s[3])*4 + s[-6] + s[6];
                        WT t1 = s[1]*6 + (s[-2] + s[4])*4 + s[-5] + s[7];
                        WT t2 = s[2]*6 + (s[-1] + s[5])*4 + s[-4] + s[8];
                        row[x] = t0; row[x+1] = t1; row[x+2] = t2;
                    }
                }
                else if( cn == 4 )
                {
                    for( ; x < width0; x += 4 )
                    {
                        const T* s = src + x*2;
                        WT t0 = s[0]*6 + (s[-4] + s[4])*4 + s[-8] + s[8];
                        WT t1 = s[1]*6 + (s[-3] + s[5])*4 + s[-7] + s[9];
                        row[x] = t0; row[x+1] = t1;
                        t0 = s[2]*6 + (s[-2] + s[6])*4 + s[-6] + s[10];
                        t1 = s[3]*6 + (s[-1] + s[7])*4 + s[-5] + s[11];
                        row[x+2] = t0; row[x+3] = t1;
                    }
                }
                else
                {
                    for( ; x < width0; x++ )
                    {
                        int sx = tabM[x];
                        row[x] = src[sx]*6 + (src[sx - cn] + src[sx + cn])*4 +
                            src[sx - cn*2] + src[sx + cn*2];
                    }
                }

                limit = dsize.width;
                tab = tabR - x;
            }
        }

        // do vertical convolution and decimation and write the result to the destination image
        for( k = 0; k < PD_SZ; k++ )
            rows[k] = buf + ((y*2 - PD_SZ/2 + k - sy0) % PD_SZ)*bufstep;
        row0 = rows[0]; row1 = rows[1]; row2 = rows[2]; row3 = rows[3]; row4 = rows[4];

        x = vecOp(rows, dst, (int)_dst.step, dsize.width);
        for( ; x < dsize.width; x++ )
            dst[x] = castOp(row2[x]*6 + (row1[x] + row3[x])*4 + row0[x] + row4[x]);
    }
}
예제 #8
0
파일: grfmt_tiff.cpp 프로젝트: Skolo/opencv
bool  TiffEncoder::write( const Mat& img, const vector<int>& /*params*/)
#endif
{
    int channels = img.channels();
    int width = img.cols, height = img.rows;
    int depth = img.depth();

    if (depth != CV_8U && depth != CV_16U)
        return false;

    int bytesPerChannel = depth == CV_8U ? 1 : 2;
    int fileStep = width * channels * bytesPerChannel;

    WLByteStream strm;

    if( m_buf )
    {
        if( !strm.open(*m_buf) )
            return false;
    }
    else
    {
#ifdef HAVE_TIFF
      return writeLibTiff(img, params);
#else
      if( !strm.open(m_filename) )
          return false;
#endif
    }

    int rowsPerStrip = (1 << 13)/fileStep;

    if( rowsPerStrip < 1 )
        rowsPerStrip = 1;

    if( rowsPerStrip > height )
        rowsPerStrip = height;

    int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;

    if( m_buf )
        m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) );

/*#if defined _DEBUG || !defined WIN32
    int uncompressedRowSize = rowsPerStrip * fileStep;
#endif*/
    int directoryOffset = 0;

    AutoBuffer<int> stripOffsets(stripCount);
    AutoBuffer<short> stripCounts(stripCount);
    AutoBuffer<uchar> _buffer(fileStep+32);
    uchar* buffer = _buffer;
    int  stripOffsetsOffset = 0;
    int  stripCountsOffset = 0;
    int  bitsPerSample = 8 * bytesPerChannel;
    int  y = 0;

    strm.putBytes( fmtSignTiffII, 4 );
    strm.putDWord( directoryOffset );

    // write an image data first (the most reasonable way
    // for compressed images)
    for( i = 0; i < stripCount; i++ )
    {
        int limit = y + rowsPerStrip;

        if( limit > height )
            limit = height;

        stripOffsets[i] = strm.getPos();

        for( ; y < limit; y++ )
        {
            if( channels == 3 )
            {
                if (depth == CV_8U)
                    icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
                else
                    icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
            }
            else
            {
              if( channels == 4 )
              {
                if (depth == CV_8U)
                    icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
                else
                    icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
              }
            }

            strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep );
        }

        stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]);
        /*assert( stripCounts[i] == uncompressedRowSize ||
                stripCounts[i] < uncompressedRowSize &&
                i == stripCount - 1);*/
    }

    if( stripCount > 2 )
    {
        stripOffsetsOffset = strm.getPos();
        for( i = 0; i < stripCount; i++ )
            strm.putDWord( stripOffsets[i] );

        stripCountsOffset = strm.getPos();
        for( i = 0; i < stripCount; i++ )
            strm.putWord( stripCounts[i] );
    }
    else if(stripCount == 2)
    {
        stripOffsetsOffset = strm.getPos();
        for (i = 0; i < stripCount; i++)
        {
            strm.putDWord (stripOffsets [i]);
        }
        stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
    }
    else
    {
        stripOffsetsOffset = stripOffsets[0];
        stripCountsOffset = stripCounts[0];
    }

    if( channels > 1 )
    {
        int bitsPerSamplePos = strm.getPos();
        strm.putWord(bitsPerSample);
        strm.putWord(bitsPerSample);
        strm.putWord(bitsPerSample);
        if( channels == 4 )
            strm.putWord(bitsPerSample);
        bitsPerSample = bitsPerSamplePos;
    }

    directoryOffset = strm.getPos();

    // write header
    strm.putWord( 9 );

    /* warning: specification 5.0 of Tiff want to have tags in
       ascending order. This is a non-fatal error, but this cause
       warning with some tools. So, keep this in ascending order */

    writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
    writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
    writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE,
              TIFF_TYPE_SHORT, channels, bitsPerSample );
    writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
    writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );

    writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
              stripCount, stripOffsetsOffset );

    writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
    writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );

    writeTag( strm, TIFF_TAG_STRIP_COUNTS,
              stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
              stripCount, stripCountsOffset );

    strm.putDWord(0);
    strm.close();

    if( m_buf )
    {
        (*m_buf)[4] = (uchar)directoryOffset;
        (*m_buf)[5] = (uchar)(directoryOffset >> 8);
        (*m_buf)[6] = (uchar)(directoryOffset >> 16);
        (*m_buf)[7] = (uchar)(directoryOffset >> 24);
    }
    else
    {
void* UniformAligner::addElement() {
	_buffer.insert(_buffer.end(), alignSize(_dataSize, _requiredAlignment), 0);
	++_numElements;

	return getElement(_numElements - 1);
}
예제 #10
0
파일: grfmt_pxm.cpp 프로젝트: 4auka/opencv
bool  PxMEncoder::write( const Mat& img, const std::vector<int>& params )
{
    bool isBinary = true;

    int  width = img.cols, height = img.rows;
    int  _channels = img.channels(), depth = (int)img.elemSize1()*8;
    int  channels = _channels > 1 ? 3 : 1;
    int  fileStep = width*(int)img.elemSize();
    int  x, y;

    for( size_t i = 0; i < params.size(); i += 2 )
        if( params[i] == CV_IMWRITE_PXM_BINARY )
            isBinary = params[i+1] != 0;

    WLByteStream strm;

    if( m_buf )
    {
        if( !strm.open(*m_buf) )
            return false;
        int t = CV_MAKETYPE(img.depth(), channels);
        m_buf->reserve( alignSize(256 + (isBinary ? fileStep*height :
            ((t == CV_8UC1 ? 4 : t == CV_8UC3 ? 4*3+2 :
            t == CV_16UC1 ? 6 : 6*3+2)*width+1)*height), 256));
    }
    else if( !strm.open(m_filename) )
        return false;

    int  lineLength;
    int  bufferSize = 128; // buffer that should fit a header

    if( isBinary )
        lineLength = width * (int)img.elemSize();
    else
        lineLength = (6 * channels + (channels > 1 ? 2 : 0)) * width + 32;

    if( bufferSize < lineLength )
        bufferSize = lineLength;

    AutoBuffer<char> _buffer(bufferSize);
    char* buffer = _buffer;

    // write header;
    sprintf( buffer, "P%c\n%d %d\n%d\n",
             '2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0),
             width, height, (1 << depth) - 1 );

    strm.putBytes( buffer, (int)strlen(buffer) );

    for( y = 0; y < height; y++ )
    {
        uchar* data = img.data + img.step*y;
        if( isBinary )
        {
            if( _channels == 3 )
            {
                if( depth == 8 )
                    icvCvt_BGR2RGB_8u_C3R( (uchar*)data, 0,
                        (uchar*)buffer, 0, cvSize(width,1) );
                else
                    icvCvt_BGR2RGB_16u_C3R( (ushort*)data, 0,
                        (ushort*)buffer, 0, cvSize(width,1) );
            }

            // swap endianness if necessary
            if( depth == 16 && !isBigEndian() )
            {
                if( _channels == 1 )
                    memcpy( buffer, data, fileStep );
                for( x = 0; x < width*channels*2; x += 2 )
                {
                    uchar v = buffer[x];
                    buffer[x] = buffer[x + 1];
                    buffer[x + 1] = v;
                }
            }
            strm.putBytes( (channels > 1 || depth > 8) ? buffer : (char*)data, fileStep );
        }
        else
        {
            char* ptr = buffer;

            if( channels > 1 )
            {
                if( depth == 8 )
                {
                    for( x = 0; x < width*channels; x += channels )
                    {
                        sprintf( ptr, "% 4d", data[x + 2] );
                        ptr += 4;
                        sprintf( ptr, "% 4d", data[x + 1] );
                        ptr += 4;
                        sprintf( ptr, "% 4d", data[x] );
                        ptr += 4;
                        *ptr++ = ' ';
                        *ptr++ = ' ';
                    }
                }
                else
                {
                    for( x = 0; x < width*channels; x += channels )
                    {
                        sprintf( ptr, "% 6d", ((ushort *)data)[x + 2] );
                        ptr += 6;
                        sprintf( ptr, "% 6d", ((ushort *)data)[x + 1] );
                        ptr += 6;
                        sprintf( ptr, "% 6d", ((ushort *)data)[x] );
                        ptr += 6;
                        *ptr++ = ' ';
                        *ptr++ = ' ';
                    }
                }
            }
            else
            {
                if( depth == 8 )
                {
                    for( x = 0; x < width; x++ )
                    {
                        sprintf( ptr, "% 4d", data[x] );
                        ptr += 4;
                    }
                }
                else
                {
                    for( x = 0; x < width; x++ )
                    {
                        sprintf( ptr, "% 6d", ((ushort *)data)[x] );
                        ptr += 6;
                    }
                }
            }

            *ptr++ = '\n';

            strm.putBytes( buffer, (int)(ptr - buffer) );
        }
    }

    strm.close();
    return true;
}
예제 #11
0
void readPackage(FILE *in) {
    static uint16_t classNextIndex = 0;

    FunctionFunctionPointer *linkingTable;
    PrepareClassFunction prepareClass;

    uint_fast8_t packageNameLength = fgetc(in);
    if (packageNameLength == 0) {
        DEBUG_LOG("Package does not have native binary");
        linkingTable = sLinkingTable;
        prepareClass = sPrepareClass;
    }
    else {
        DEBUG_LOG("Package has native binary");
        auto name = new char[packageNameLength];
        fread(name, sizeof(char), packageNameLength, in);

        uint16_t major = readUInt16(in);
        uint16_t minor = readUInt16(in);

        DEBUG_LOG("Package is named %s and has version %d.%d.x", name, major, minor);

        PackageLoadingState s = packageLoad(name, major, minor, &linkingTable, &prepareClass);

        if (s == PACKAGE_INAPPROPRIATE_MAJOR) {
            error("Installed version of package \"%s\" is incompatible with required version %d.%d. (How did you made Emojicode load this version of the package?!)", name, major, minor);
        }
        else if (s == PACKAGE_INAPPROPRIATE_MINOR) {
            error("Installed version of package \"%s\" is incompatible with required version %d.%d. Please update to the latest minor version.", name, major, minor);
        }
        else if (s == PACKAGE_LOADING_FAILED) {
            error("Could not load package \"%s\" %s.", name, packageError());
        }

        delete [] name;
    }

    for (int classCount = readUInt16(in); classCount > 0; classCount--) {
        DEBUG_LOG("➡️ Still %d class(es) to load", classCount);
        EmojicodeChar name = readEmojicodeChar(in);

        auto *klass = new Class;
        classTable[classNextIndex++] = klass;

        DEBUG_LOG("Loading class %X into %p", name, klass);

        klass->superclass = classTable[readUInt16(in)];
        int instanceVariableCount = readUInt16(in);

        int methodCount = readUInt16(in);
        klass->methodsVtable = new Function*[methodCount];

        bool inheritsInitializers = fgetc(in);
        int initializerCount = readUInt16(in);
        klass->initializersVtable = new Function*[initializerCount];

        DEBUG_LOG("Inherting intializers: %s", inheritsInitializers ? "true" : "false");

        DEBUG_LOG("%d instance variable(s); %d methods; %d initializer(s)",
                  instanceVariableCount, initializerCount, methodCount);

        uint_fast16_t localMethodCount = readUInt16(in);
        uint_fast16_t localInitializerCount = readUInt16(in);

        DEBUG_LOG("Reading %d method(s) and %d initializer(s) that are not inherited or overriden",
                  localMethodCount, localInitializerCount);

        if (klass != klass->superclass) {
            memcpy(klass->methodsVtable, klass->superclass->methodsVtable, methodCount * sizeof(Function*));
            if (inheritsInitializers) {
                memcpy(klass->initializersVtable, klass->superclass->initializersVtable,
                       initializerCount * sizeof(Function*));
            }
        }
        else {
            klass->superclass = nullptr;
        }

        for (uint_fast16_t i = 0; i < localMethodCount; i++) {
            DEBUG_LOG("Reading method %d", i);
            readFunction(klass->methodsVtable, in, linkingTable);
        }

        for (uint_fast16_t i = 0; i < localInitializerCount; i++) {
            DEBUG_LOG("Reading initializer %d", i);
            readFunction(klass->initializersVtable, in, linkingTable);
        }

        readProtocolTable(klass->protocolTable, klass->methodsVtable, in);

        // Allow inheritance from class with value, e.g. list
        klass->valueSize = klass->superclass && klass->superclass->valueSize ? klass->superclass->valueSize : 0;
        prepareClass(klass, name);
        klass->size = alignSize(sizeof(Object) + klass->valueSize + instanceVariableCount * sizeof(Value));

        klass->instanceVariableRecordsCount = readUInt16(in);
        klass->instanceVariableRecords = new FunctionObjectVariableRecord[klass->instanceVariableRecordsCount];
        for (size_t i = 0; i < klass->instanceVariableRecordsCount; i++) {
            klass->instanceVariableRecords[i].variableIndex = readUInt16(in);
            klass->instanceVariableRecords[i].condition = readUInt16(in);
            klass->instanceVariableRecords[i].type = static_cast<ObjectVariableType>(readUInt16(in));
        }

        DEBUG_LOG("Read %d object variable records", klass->instanceVariableRecordsCount);
    }

    for (int functionCount = readUInt16(in); functionCount > 0; functionCount--) {
        DEBUG_LOG("➡️ Still %d functions to come", functionCount);
        readFunction(functionTable, in, linkingTable);
    }
}