libembroidery-sys 0.1.2

Rust FFI bindings for libembroidery
Documentation
#include "format-csd.h"
#include "helpers-binary.h"
#include "helpers-misc.h"
#include "emb-file.h"
#include "emb-logging.h"
#include <stdlib.h>

#define CsdSubMaskSize  479
#define CsdXorMaskSize  501

static char _subMask[CsdSubMaskSize];
static char _xorMask[CsdXorMaskSize];

static void BuildDecryptionTable(int seed)
{
    int i;
    const int mul1 = 0x41C64E6D;
    const int add1 = 0x3039;

    for(i = 0; i < CsdSubMaskSize; i++)
    {
        seed *= mul1;
        seed += add1;
        _subMask[i] = (char) ((seed >> 16) & 0xFF);
    }
    for(i = 0; i < CsdXorMaskSize; i++)
    {
        seed *= mul1;
        seed += add1;
        _xorMask[i] = (char) ((seed >> 16) & 0xFF);
    }
}

static unsigned char DecodeCsdByte(long fileOffset, unsigned char val, int type)
{
    static const unsigned char _decryptArray[] =
    {
          0x43, 0x6E, 0x72, 0x7A, 0x76, 0x6C, 0x61, 0x6F, 0x7C, 0x29, 0x5D, 0x62, 0x60, 0x6E, 0x61, 0x62, 0x20
        , 0x41, 0x66, 0x6A, 0x3A, 0x35, 0x5A, 0x63, 0x7C, 0x37, 0x3A, 0x2A, 0x25, 0x24, 0x2A, 0x33, 0x00, 0x10
        , 0x14, 0x03, 0x72, 0x4C, 0x48, 0x42, 0x08, 0x7A, 0x5E, 0x0B, 0x6F, 0x45, 0x47, 0x5F, 0x40, 0x54, 0x5C
        , 0x57, 0x55, 0x59, 0x53, 0x3A, 0x32, 0x6F, 0x53, 0x54, 0x50, 0x5C, 0x4A, 0x56, 0x2F, 0x2F, 0x62, 0x2C
        , 0x22, 0x65, 0x25, 0x28, 0x38, 0x30, 0x38, 0x22, 0x2B, 0x25, 0x3A, 0x6F, 0x27, 0x38, 0x3E, 0x3F, 0x74
        , 0x37, 0x33, 0x77, 0x2E, 0x30, 0x3D, 0x34, 0x2E, 0x32, 0x2B, 0x2C, 0x0C, 0x18, 0x42, 0x13, 0x16, 0x0A
        , 0x15, 0x02, 0x0B, 0x1C, 0x1E, 0x0E, 0x08, 0x60, 0x64, 0x0D, 0x09, 0x51, 0x25, 0x1A, 0x18, 0x16, 0x19
        , 0x1A, 0x58, 0x10, 0x14, 0x5B, 0x08, 0x15, 0x1B, 0x5F, 0xD5, 0xD2, 0xAE, 0xA3, 0xC1, 0xF0, 0xF4, 0xE8
        , 0xF8, 0xEC, 0xA6, 0xAB, 0xCD, 0xF8, 0xFD, 0xFB, 0xE2, 0xF0, 0xFE, 0xFA, 0xF5, 0xB5, 0xF7, 0xF9, 0xFC
        , 0xB9, 0xF5, 0xEF, 0xF4, 0xF8, 0xEC, 0xBF, 0xC3, 0xCE, 0xD7, 0xCD, 0xD0, 0xD7, 0xCF, 0xC2, 0xDB, 0xA4
        , 0xA0, 0xB0, 0xAF, 0xBE, 0x98, 0xE2, 0xC2, 0x91, 0xE5, 0xDC, 0xDA, 0xD2, 0x96, 0xC4, 0x98, 0xF8, 0xC9
        , 0xD2, 0xDD, 0xD3, 0x9E, 0xDE, 0xAE, 0xA5, 0xE2, 0x8C, 0xB6, 0xAC, 0xA3, 0xA9, 0xBC, 0xA8, 0xA6, 0xEB
        , 0x8B, 0xBF, 0xA1, 0xAC, 0xB5, 0xA3, 0xBB, 0xB6, 0xA7, 0xD8, 0xDC, 0x9A, 0xAA, 0xF9, 0x82, 0xFB, 0x9D
        , 0xB9, 0xAB, 0xB3, 0x94, 0xC1, 0xA0, 0x8C, 0x8B, 0x8E, 0x95, 0x8F, 0x87, 0x99, 0xE7, 0xE1, 0xA3, 0x83
        , 0x8B, 0xCF, 0xA3, 0x85, 0x9D, 0x83, 0xD4, 0xB7, 0x83, 0x84, 0x91, 0x97, 0x9F, 0x88, 0x8F, 0xDD, 0xAD
        , 0x90
    };
    int newOffset;

    fileOffset = fileOffset - 1;
    if(type != 0)
    {
        int final;
        int fileOffsetHigh = (int) (fileOffset & 0xFFFFFF00);
        int fileOffsetLow = (int) (fileOffset & 0xFF);

        newOffset = fileOffsetLow;
        fileOffsetLow = fileOffsetHigh;
        final = fileOffsetLow%0x300;
        if(final != 0x100 && final != 0x200)
        {
            newOffset = _decryptArray[newOffset] | fileOffsetHigh;
        }
        else if(final != 0x100 && final == 0x200)
        {
            if(newOffset == 0)
            {
                fileOffsetHigh = fileOffsetHigh - 0x100;
            }
            newOffset = _decryptArray[newOffset] | fileOffsetHigh;
        }
        else if(newOffset != 1 && newOffset != 0)
        {
            newOffset = _decryptArray[newOffset] | fileOffsetHigh;
        }
        else
        {
            fileOffsetHigh = fileOffsetHigh - 0x100;
            newOffset = _decryptArray[newOffset] | fileOffsetHigh;
        }
    }
    else
    {
        newOffset = (int) fileOffset;
    }
    return ((unsigned char) ((unsigned char) (val ^ _xorMask[newOffset%CsdXorMaskSize]) - _subMask[newOffset%CsdSubMaskSize]));
}

/*! Reads a file with the given \a fileName and loads the data into \a pattern.
 *  Returns \c true if successful, otherwise returns \c false. */
int readCsd(EmbPattern* pattern, const char* fileName)
{
    int i, type = 0;
    unsigned char identifier[8];
    unsigned char unknown1, unknown2;
    char dx = 0, dy = 0;
    int colorChange = -1;
    int flags;
    char endOfStream = 0;
    EmbFile* file = 0;
    unsigned char colorOrder[14];

    if(!pattern) { embLog_error("format-csd.c readCsd(), pattern argument is null\n"); return 0; }
    if(!fileName) { embLog_error("format-csd.c readCsd(), fileName argument is null\n"); return 0; }

    file = embFile_open(fileName, "rb");
    if(!file)
    {
        embLog_error("format-csd.c readCsd(), cannot open %s for reading\n", fileName);
        return 0;
    }

    binaryReadBytes(file, identifier, 8); /* TODO: check return value */

    if(identifier[0] != 0x7C && identifier[2] != 0xC3)
    {
        type = 1;
    }
    if(type == 0)
    {
        BuildDecryptionTable(0xC);
    }
    else
    {
        BuildDecryptionTable(identifier[0]);
    }
    embFile_seek(file, 8, SEEK_SET);
    for(i = 0; i < 16; i++)
    {
        EmbThread thread;
        thread.color.r = DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);
        thread.color.g = DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);
        thread.color.b = DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);
        thread.catalogNumber = "";
        thread.description = "";
        embPattern_addThread(pattern, thread);
    }
    unknown1 = DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);
    unknown2 = DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);

    for(i = 0; i < 14; i++)
    {
        colorOrder[i] = (unsigned char) DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);
    }
    for(i = 0; !endOfStream; i++)
    {
        char negativeX, negativeY;
        unsigned char b0 = DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);
        unsigned char b1 = DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);
        unsigned char b2 = DecodeCsdByte(embFile_tell(file), binaryReadByte(file), type);

        if(b0 == 0xF8 || b0 == 0x87 || b0 == 0x91)
        {
            break;
        }
        negativeX = ((b0 & 0x20) > 0);
        negativeY = ((b0 & 0x40) > 0);
        b0 = (unsigned char)(b0 & (0xFF ^ 0xE0));

        if((b0 & 0x1F) == 0) flags = NORMAL;
        else if((b0 & 0x0C) > 0)
        {
            flags = STOP;
            if(colorChange >= 14)
            {
                printf("Invalid color change detected\n");
            }
            embPattern_changeColor(pattern, colorOrder[colorChange  % 14]);
            colorChange += 1;
        }
        else if((b0 & 0x1F) > 0) flags = TRIM;
        else flags = NORMAL;
        dx = (char) b2;
        dy = (char) b1;
        if(negativeX) dx = (char) -dx;
        if(negativeY) dy = (char) -dy;
        if(flags == STOP) embPattern_addStitchRel(pattern, 0, 0, flags, 1);
        else embPattern_addStitchRel(pattern, dx / 10.0, dy / 10.0, flags, 1);
    }
    embFile_close(file);

    /* Check for an END stitch and add one if it is not present */
    if(pattern->lastStitch->stitch.flags != END)
        embPattern_addStitchRel(pattern, 0, 0, END, 1);

    return 1;
}

/*! Writes the data from \a pattern to a file with the given \a fileName.
 *  Returns \c true if successful, otherwise returns \c false. */
int writeCsd(EmbPattern* pattern, const char* fileName)
{
    if(!pattern) { embLog_error("format-csd.c writeCsd(), pattern argument is null\n"); return 0; }
    if(!fileName) { embLog_error("format-csd.c writeCsd(), fileName argument is null\n"); return 0; }

    if(!embStitchList_count(pattern->stitchList))
    {
        embLog_error("format-csd.c writeCsd(), pattern contains no stitches\n");
        return 0;
    }

    /* Check for an END stitch and add one if it is not present */
    if(pattern->lastStitch->stitch.flags != END)
        embPattern_addStitchRel(pattern, 0, 0, END, 1);

    /* TODO: embFile_open() needs to occur here after the check for no stitches */

    return 0; /*TODO: finish writeCsd */
}

/* kate: bom off; indent-mode cstyle; indent-width 4; replace-trailing-space-save on; */