Add LZW support for Teledisk 1.x advanced compressed files.
This commit is contained in:
@@ -16,3 +16,6 @@
|
||||
add_library(fdd OBJECT fdd.c fdc.c fdc_magitronic.c fdc_monster.c fdc_pii15xb.c
|
||||
fdi2raw.c fdd_common.c fdd_86f.c fdd_fdi.c fdd_imd.c fdd_img.c fdd_pcjs.c
|
||||
fdd_mfm.c fdd_td0.c)
|
||||
|
||||
add_subdirectory(lzw)
|
||||
target_link_libraries(86Box lzw)
|
||||
|
@@ -42,6 +42,7 @@
|
||||
#include <86box/fdd_86f.h>
|
||||
#include <86box/fdd_td0.h>
|
||||
#include <86box/fdc.h>
|
||||
#include "lzw/lzw.h"
|
||||
|
||||
#define BUFSZ 512 /* new input buffer */
|
||||
#define TD0_MAX_BUFSZ (1024UL * 1024UL * 4UL)
|
||||
@@ -124,7 +125,9 @@ typedef struct td0_t {
|
||||
uint8_t xdf_ordered_pos[256][2];
|
||||
uint8_t interleave_ordered_pos[256][2];
|
||||
|
||||
uint8_t *lzw_buf;
|
||||
uint8_t *imagebuf;
|
||||
|
||||
uint8_t *processed_buf;
|
||||
} td0_t;
|
||||
|
||||
@@ -650,11 +653,20 @@ td0_initialize(int drive)
|
||||
head_count = header[9];
|
||||
|
||||
if (header[0] == 't') {
|
||||
td0_log("TD0: File is compressed\n");
|
||||
disk_decode.fdd_file = dev->fp;
|
||||
state_init_Decode(&disk_decode);
|
||||
disk_decode.fdd_file_offset = 12;
|
||||
state_Decode(&disk_decode, dev->imagebuf, TD0_MAX_BUFSZ);
|
||||
if (((header[4] / 10) % 10) == 2) {
|
||||
td0_log("TD0: File is compressed (TeleDisk 2.x, LZHUF)\n");
|
||||
disk_decode.fdd_file = dev->fp;
|
||||
state_init_Decode(&disk_decode);
|
||||
disk_decode.fdd_file_offset = 12;
|
||||
state_Decode(&disk_decode, dev->imagebuf, TD0_MAX_BUFSZ);
|
||||
} else {
|
||||
td0_log("TD0: File is compressed (TeleDisk 1.x, LZW)\n");
|
||||
if (fseek(dev->fp, 12, SEEK_SET) == -1)
|
||||
fatal("td0_initialize(): Error seeking to offet 12\n");
|
||||
if (fread(dev->lzw_buf, 1, file_size - 12, dev->fp) != (file_size - 12))
|
||||
fatal("td0_initialize(): Error reading LZW-encoded buffer\n");
|
||||
LZWDecodeFile((char *) dev->imagebuf, (char *) dev->lzw_buf, NULL, file_size - 12);
|
||||
}
|
||||
} else {
|
||||
td0_log("TD0: File is uncompressed\n");
|
||||
if (fseek(dev->fp, 12, SEEK_SET) == -1)
|
||||
@@ -1224,10 +1236,9 @@ td0_load(int drive, char *fn)
|
||||
|
||||
/* Allocate the processing buffers. */
|
||||
i = 1024UL * 1024UL * 4UL;
|
||||
dev->imagebuf = (uint8_t *) malloc(i);
|
||||
memset(dev->imagebuf, 0x00, i);
|
||||
dev->processed_buf = (uint8_t *) malloc(i);
|
||||
memset(dev->processed_buf, 0x00, i);
|
||||
dev->lzw_buf = (uint8_t *) calloc(1, i);
|
||||
dev->imagebuf = (uint8_t *) calloc(1, i);
|
||||
dev->processed_buf = (uint8_t *) calloc(1, i);
|
||||
|
||||
if (!td0_initialize(drive)) {
|
||||
td0_log("TD0: Failed to initialize\n");
|
||||
@@ -1268,6 +1279,8 @@ td0_close(int drive)
|
||||
|
||||
d86f_unregister(drive);
|
||||
|
||||
if (dev->lzw_buf)
|
||||
free(dev->lzw_buf);
|
||||
if (dev->imagebuf)
|
||||
free(dev->imagebuf);
|
||||
if (dev->processed_buf)
|
||||
|
16
src/floppy/lzw/CMakeLists.txt
Normal file
16
src/floppy/lzw/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
# running old operating systems and software designed for IBM
|
||||
# PC systems and compatibles from 1981 through fairly recent
|
||||
# system designs based on the PCI bus.
|
||||
#
|
||||
# This file is part of the 86Box distribution.
|
||||
#
|
||||
# CMake build script.
|
||||
#
|
||||
# Authors: David Hrdlička, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# Copyright 2020-2021 David Hrdlička.
|
||||
#
|
||||
|
||||
add_library(lzw STATIC lzwdecode.c lzwencode.c)
|
49
src/floppy/lzw/lzw.h
Normal file
49
src/floppy/lzw/lzw.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/***************************************************************************
|
||||
* Header for Lempel-Ziv-Welch Encoding and Decoding Library
|
||||
*
|
||||
* File : lzw.h
|
||||
* Purpose : Provides prototypes for functions that use Lempel-Ziv-Welch
|
||||
* coding to encode/decode files.
|
||||
* Author : Michael Dipperstein
|
||||
* Date : January 30, 2004
|
||||
*
|
||||
****************************************************************************
|
||||
*
|
||||
* LZW: An ANSI C Lempel-Ziv-Welch Encoding/Decoding Routines
|
||||
* Copyright (C) 2005, 2007, 2014 by
|
||||
* Michael Dipperstein (mdipperstein@gmail.com)
|
||||
*
|
||||
* This file is part of the lzw library.
|
||||
*
|
||||
* The lzw 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The lzw 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _LZW_H_
|
||||
#define _LZW_H_
|
||||
|
||||
/***************************************************************************
|
||||
* CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* PROTOTYPES
|
||||
***************************************************************************/
|
||||
/* encode inFile */
|
||||
int LZWEncodeFile(char *dest, char *src, uint64_t *dst_len, uint64_t src_len);
|
||||
|
||||
/* decode inFile*/
|
||||
int LZWDecodeFile(char *dest, char *src, uint64_t *dst_len, uint64_t src_len);
|
||||
|
||||
#endif /* ndef _LZW_H_ */
|
269
src/floppy/lzw/lzwdecode.c
Normal file
269
src/floppy/lzw/lzwdecode.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/***************************************************************************
|
||||
* Lempel-Ziv-Welch Decoding Functions
|
||||
*
|
||||
* File : lzwdecode.c
|
||||
* Purpose : Provides a function for decoding Lempel-Ziv-Welch encoded
|
||||
* file streams
|
||||
* Author : Michael Dipperstein
|
||||
* Date : January 30, 2005
|
||||
*
|
||||
****************************************************************************
|
||||
*
|
||||
* LZW: An ANSI C Lempel-Ziv-Welch Encoding/Decoding Routines
|
||||
* Copyright (C) 2005, 2007, 2014, 2017 by
|
||||
* Michael Dipperstein (mdipperstein@gmail.com)
|
||||
*
|
||||
* This file is part of the lzw library.
|
||||
*
|
||||
* The lzw 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The lzw 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* INCLUDED FILES
|
||||
***************************************************************************/
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "lzw.h"
|
||||
#include "lzwlocal.h"
|
||||
|
||||
/***************************************************************************
|
||||
* TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t suffixChar; /* last char in encoded string */
|
||||
uint16_t prefixCode; /* code for remaining chars in string */
|
||||
} decode_dictionary_t;
|
||||
|
||||
/***************************************************************************
|
||||
* CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* MACROS
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* GLOBAL VARIABLES
|
||||
***************************************************************************/
|
||||
|
||||
/* dictionary of string the code word is the dictionary index */
|
||||
static decode_dictionary_t dictionary[(MAX_CODES - FIRST_CODE)];
|
||||
|
||||
/***************************************************************************
|
||||
* PROTOTYPES
|
||||
***************************************************************************/
|
||||
static uint8_t DecodeRecursive(unsigned int code, char **dest);
|
||||
|
||||
/* read encoded data */
|
||||
static int GetCodeWord(char *src);
|
||||
|
||||
static uint16_t bufPos = 0x0000;
|
||||
static uint16_t bufLen = 0x0000;
|
||||
|
||||
static uint32_t bufOutPos = 0x00000000;
|
||||
|
||||
/***************************************************************************
|
||||
* FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* Function : LZWDecodeFile
|
||||
* Description: This routine reads an input file 1 encoded string at a
|
||||
* time and decodes it using the LZW algorithm.
|
||||
* Parameters : fpIn - pointer to the open binary file to decode
|
||||
* fpOut - pointer to the open binary file to write decoded
|
||||
* output
|
||||
* Effects : fpIn is decoded using the LZW algorithm with CODE_LEN codes
|
||||
* and written to fpOut. Neither file is closed after exit.
|
||||
* Returned : 0 for success, -1 for failure. errno will be set in the
|
||||
* event of a failure.
|
||||
***************************************************************************/
|
||||
int
|
||||
LZWDecodeFile_Internal(char *dest, char *src)
|
||||
{
|
||||
uint16_t nextCode; /* value of next code */
|
||||
uint16_t lastCode; /* last decoded code word */
|
||||
int code; /* code word to decode */
|
||||
uint8_t c; /* last decoded character */
|
||||
|
||||
/* validate arguments */
|
||||
if (dest == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bufPos = 0x0000;
|
||||
bufOutPos = 0x00000000;
|
||||
|
||||
/* initialize for decoding */
|
||||
nextCode = FIRST_CODE; /* code for next (first) string */
|
||||
|
||||
/* first code from file must be a character. use it for initial values */
|
||||
lastCode = GetCodeWord(src);
|
||||
c = lastCode;
|
||||
*(dest++) = lastCode;
|
||||
bufOutPos++;
|
||||
|
||||
/* decode rest of file */
|
||||
while ((int)(code = GetCodeWord(src)) != EOF) {
|
||||
if (code < nextCode) {
|
||||
/* we have a known code. decode it */
|
||||
c = DecodeRecursive(code, &dest);
|
||||
} else {
|
||||
/***************************************************************
|
||||
* We got a code that's not in our dictionary. This must be due
|
||||
* to the string + char + string + char + string exception.
|
||||
* Build the decoded string using the last character + the
|
||||
* string from the last code.
|
||||
***************************************************************/
|
||||
unsigned char tmp;
|
||||
|
||||
tmp = c;
|
||||
c = DecodeRecursive(lastCode, &dest);
|
||||
*(dest++) = tmp;
|
||||
bufOutPos++;
|
||||
}
|
||||
|
||||
/* if room, add new code to the dictionary */
|
||||
if (nextCode < MAX_CODES) {
|
||||
dictionary[nextCode - FIRST_CODE].prefixCode = lastCode;
|
||||
dictionary[nextCode - FIRST_CODE].suffixChar = c;
|
||||
nextCode++;
|
||||
}
|
||||
|
||||
/* save character and code for use in unknown code word case */
|
||||
lastCode = code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
LZWDecodeFile(char *dest, char *src, uint64_t *dst_len, uint64_t src_len)
|
||||
{
|
||||
uint16_t size = 0x0000;
|
||||
uint64_t pos = 0x0000000000000000ULL;
|
||||
|
||||
/* validate arguments */
|
||||
if ((dest == NULL) || (src == NULL)) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dst_len != NULL)
|
||||
*dst_len = 0x0000000000000000ULL;
|
||||
|
||||
while (1) {
|
||||
size = *(uint16_t *) src;
|
||||
src += 2;
|
||||
bufLen = size;
|
||||
size >>= 1;
|
||||
if (bufLen & 1)
|
||||
size++;
|
||||
if (size > 0x1800)
|
||||
return -1;
|
||||
LZWDecodeFile_Internal(dest, src);
|
||||
src += size;
|
||||
dest += bufOutPos;
|
||||
if (dst_len != NULL)
|
||||
*dst_len += bufOutPos;
|
||||
pos += (size + 2);
|
||||
if ((size < 0x1800) || (pos >= src_len))
|
||||
/* We have just decoded a block smaller than 0x3000 bytes,
|
||||
this means this has been the last block, end. */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : DecodeRecursive
|
||||
* Description: This function uses the dictionary to decode a code word
|
||||
* into the string it represents and write it to the output
|
||||
* file. The string is actually built in reverse order and
|
||||
* recursion is used to write it out in the correct order.
|
||||
* Parameters : code - the code word to decode
|
||||
* fpOut - the file that the decoded code word is written to
|
||||
* Effects : Decoded code word is written to a file
|
||||
* Returned : The first character in the decoded string
|
||||
***************************************************************************/
|
||||
static uint8_t
|
||||
DecodeRecursive(unsigned int code, char **dest)
|
||||
{
|
||||
unsigned char c;
|
||||
unsigned char firstChar;
|
||||
|
||||
if (code >= FIRST_CODE) {
|
||||
/* code word is string + c */
|
||||
c = dictionary[code - FIRST_CODE].suffixChar;
|
||||
code = dictionary[code - FIRST_CODE].prefixCode;
|
||||
|
||||
/* evaluate new code word for remaining string */
|
||||
firstChar = DecodeRecursive(code, dest);
|
||||
} else {
|
||||
/* code word is just c */
|
||||
c = code;
|
||||
firstChar = code;
|
||||
}
|
||||
|
||||
*((*dest)++) = c;
|
||||
bufOutPos++;
|
||||
return firstChar;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : GetCodeWord
|
||||
* Description: This function reads and returns a code word from an
|
||||
* encoded file. In order to deal with endian issue the
|
||||
* code word is read least significant byte followed by the
|
||||
* remaining bits.
|
||||
* Parameters : fpIn - file containing the encoded data
|
||||
* codeLen - number of bits in code word
|
||||
* Effects : code word is read from encoded input
|
||||
* Returned : The next code word in the encoded file. EOF if the end
|
||||
* of file has been reached.
|
||||
*
|
||||
* NOTE: If the code word contains more than 16 bits, this routine should
|
||||
* be modified to read in all the bytes from least significant to
|
||||
* most significant followed by any left over bits.
|
||||
***************************************************************************/
|
||||
static int
|
||||
GetCodeWord(char *src)
|
||||
{
|
||||
int code = 0;
|
||||
static unsigned int realPos;
|
||||
|
||||
realPos = bufPos >> 1;
|
||||
|
||||
if (bufPos >= bufLen)
|
||||
/* End of buffer. */
|
||||
code = EOF;
|
||||
else if (bufPos & 1)
|
||||
/* Odd position. */
|
||||
code = (((uint8_t) src[realPos] & 0xf0) >> 4) | ((uint8_t) src[realPos + 1] << 4);
|
||||
else
|
||||
/* Even position. */
|
||||
code = ((uint8_t) src[realPos] & 0xff) | (((uint8_t) src[realPos + 1] & 0xf) << 8);
|
||||
|
||||
bufPos += 3;
|
||||
|
||||
return code;
|
||||
}
|
454
src/floppy/lzw/lzwencode.c
Normal file
454
src/floppy/lzw/lzwencode.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/***************************************************************************
|
||||
* Lempel-Ziv-Welch Encoding Functions
|
||||
*
|
||||
* File : lzwencode.c
|
||||
* Purpose : Provides a function for Lempel-Ziv-Welch encoding of file
|
||||
* streams
|
||||
* Author : Michael Dipperstein
|
||||
* Date : January 30, 2005
|
||||
*
|
||||
****************************************************************************
|
||||
*
|
||||
* LZW: An ANSI C Lempel-Ziv-Welch Encoding/Decoding Routines
|
||||
* Copyright (C) 2005, 2007, 2014, 2017 by
|
||||
* Michael Dipperstein (mdipperstein@gmail.com)
|
||||
*
|
||||
* This file is part of the lzw library.
|
||||
*
|
||||
* The lzw 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The lzw 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* INCLUDED FILES
|
||||
***************************************************************************/
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "lzw.h"
|
||||
#include "lzwlocal.h"
|
||||
|
||||
/***************************************************************************
|
||||
* TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
/* node in dictionary tree */
|
||||
typedef struct dict_node_t
|
||||
{
|
||||
unsigned int codeWord; /* code word for this entry */
|
||||
unsigned char suffixChar; /* last char in encoded string */
|
||||
unsigned int prefixCode; /* code for remaining chars in string */
|
||||
|
||||
/* pointer to child nodes */
|
||||
struct dict_node_t *left; /* child with < key */
|
||||
struct dict_node_t *right; /* child with >= key */
|
||||
} dict_node_t;
|
||||
|
||||
/***************************************************************************
|
||||
* CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* MACROS
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* GLOBAL VARIABLES
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* dictionary tree node create/free */
|
||||
static dict_node_t *MakeNode(const unsigned int codeWord, const unsigned int prefixCode,
|
||||
const unsigned char suffixChar);
|
||||
static void FreeTree(dict_node_t *node);
|
||||
|
||||
/* searches tree for matching dictionary entry */
|
||||
static dict_node_t *FindDictionaryEntry(dict_node_t *root, const int unsigned prefixCode,
|
||||
const unsigned char c);
|
||||
|
||||
/* makes key from prefix code and character */
|
||||
static unsigned int MakeKey(const unsigned int prefixCode, const unsigned char suffixChar);
|
||||
|
||||
/* write encoded data */
|
||||
static int PutCodeWord(char *dest, int code);
|
||||
|
||||
static char *src_base;
|
||||
static uint64_t src_length = 0x0000000000000000ULL;
|
||||
|
||||
static uint32_t bufPos = 0x00000000;
|
||||
static uint32_t bufInPos = 0x00000000;
|
||||
|
||||
static int
|
||||
is_eob(char *src)
|
||||
{
|
||||
return ((uint64_t) (uintptr_t) (src - src_base)) >= src_length;
|
||||
}
|
||||
|
||||
static int
|
||||
get_char(char **src)
|
||||
{
|
||||
int ret = EOF;
|
||||
|
||||
if (!is_eob(*src)) {
|
||||
ret = (uint8_t) **src;
|
||||
(*src)++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
static int
|
||||
LZWEncodeFile_Internal(char *dest, char *src)
|
||||
{
|
||||
unsigned int code; /* code for current string */
|
||||
unsigned int nextCode; /* next available code index */
|
||||
int c; /* character to add to string */
|
||||
|
||||
dict_node_t *dictRoot; /* root of dictionary tree */
|
||||
dict_node_t *node; /* node of dictionary tree */
|
||||
|
||||
/* validate arguments */
|
||||
if (src == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* initialize dictionary as empty */
|
||||
dictRoot = NULL;
|
||||
|
||||
nextCode = FIRST_CODE; /* code for next (first) string */
|
||||
|
||||
bufPos = 0x00000000;
|
||||
bufInPos = 0x00000000;
|
||||
|
||||
/* now start the actual encoding process */
|
||||
|
||||
c = get_char(&src);
|
||||
|
||||
if (c == EOF)
|
||||
return -1; /* empty file */
|
||||
else {
|
||||
bufInPos++;
|
||||
code = c; /* start with code string = first character */
|
||||
}
|
||||
|
||||
/* create a tree root from 1st 2 character string */
|
||||
if ((c = get_char(&src)) != EOF) {
|
||||
bufInPos++;
|
||||
|
||||
/* special case for NULL root */
|
||||
dictRoot = MakeNode(nextCode, code, c);
|
||||
|
||||
if (dictRoot == NULL) {
|
||||
perror("Making Dictionary Root");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nextCode++;
|
||||
|
||||
/* write code for 1st char */
|
||||
(void) PutCodeWord(dest, code);
|
||||
|
||||
/* new code is just 2nd char */
|
||||
code = c;
|
||||
}
|
||||
|
||||
/* now encode normally */
|
||||
while ((c = get_char(&src)) != EOF) {
|
||||
/* look for code + c in the dictionary */
|
||||
node = FindDictionaryEntry(dictRoot, code, c);
|
||||
|
||||
if ((node->prefixCode == code) && (node->suffixChar == c))
|
||||
/* code + c is in the dictionary, make it's code the new code */
|
||||
code = node->codeWord;
|
||||
else {
|
||||
/* code + c is not in the dictionary, add it if there's room */
|
||||
if (nextCode < MAX_CODES) {
|
||||
dict_node_t *tmp = MakeNode(nextCode, code, c);
|
||||
|
||||
if (tmp == NULL) {
|
||||
perror("Making Dictionary Node");
|
||||
FreeTree(dictRoot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nextCode++;
|
||||
|
||||
if (MakeKey(code, c) < MakeKey(node->prefixCode, node->suffixChar))
|
||||
node->left = tmp;
|
||||
else
|
||||
node->right = tmp;
|
||||
}
|
||||
|
||||
/* write out code for the string before c was added */
|
||||
if (PutCodeWord(dest, code))
|
||||
break;
|
||||
|
||||
/* new code is just c */
|
||||
code = c;
|
||||
}
|
||||
|
||||
bufInPos++;
|
||||
}
|
||||
|
||||
/* no more input. write out last of the code. */
|
||||
(void) PutCodeWord(dest, code);
|
||||
|
||||
/* free the dictionary */
|
||||
FreeTree(dictRoot);
|
||||
|
||||
return (c == EOF) ? 1 : 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : LZWEncodeFile
|
||||
* Description: This routine reads an input file 1 character at a time and
|
||||
* writes out an LZW encoded version of that file.
|
||||
* Parameters : fpIn - pointer to the open binary file to encode
|
||||
* fpOut - pointer to the open binary file to write encoded
|
||||
* output
|
||||
* Effects : fpIn is encoded using the LZW algorithm with CODE_LEN codes
|
||||
* and written to fpOut. Neither file is closed after exit.
|
||||
* Returned : 0 for success, -1 for failure. errno will be set in the
|
||||
* event of a failure.
|
||||
***************************************************************************/
|
||||
int
|
||||
LZWEncodeFile(char *dest, char *src, uint64_t *dst_len, uint64_t src_len)
|
||||
{
|
||||
uint64_t pos = 0x0000000000000000ULL;
|
||||
|
||||
/* validate arguments */
|
||||
if ((dest == NULL) || (src == NULL)) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dst_len != NULL)
|
||||
*dst_len = 0x0000000000000000ULL;
|
||||
|
||||
src_base = src;
|
||||
src_length = src_len;
|
||||
|
||||
while (1) {
|
||||
int ret = LZWEncodeFile_Internal(dest + 2, src);
|
||||
if (ret == -1)
|
||||
break;
|
||||
*(uint16_t *) dest = bufPos;
|
||||
if (bufPos & 1)
|
||||
bufPos = (bufPos >> 1) + 1;
|
||||
else
|
||||
bufPos >>= 1;
|
||||
dest += (bufPos + 2);
|
||||
if (dst_len != NULL)
|
||||
*dst_len += (bufPos + 2);
|
||||
/* TODO: Why do we need this - 1 clunkfest? */
|
||||
src += bufInPos;
|
||||
pos += bufInPos;
|
||||
if ((ret == 1) || (pos >= src_len) || (bufPos < 0x1800))
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : MakeKey
|
||||
* Description: This routine creates a simple key from a prefix code and
|
||||
* an appended character. The key may be used to establish
|
||||
* an order when building/searching a dictionary tree.
|
||||
* Parameters : prefixCode - code for all but the last character of a
|
||||
* string.
|
||||
* suffixChar - the last character of a string
|
||||
* Effects : None
|
||||
* Returned : Key built from string represented as a prefix + char. Key
|
||||
* format is {ms nibble of c} + prefix + {ls nibble of c}
|
||||
***************************************************************************/
|
||||
static unsigned int
|
||||
MakeKey(const unsigned int prefixCode, const unsigned char suffixChar)
|
||||
{
|
||||
unsigned int key;
|
||||
|
||||
/* position ms nibble */
|
||||
key = suffixChar & 0xF0;
|
||||
key <<= MAX_CODE_LEN;
|
||||
|
||||
/* include prefix code */
|
||||
key |= (prefixCode << 4);
|
||||
|
||||
/* inclulde ls nibble */
|
||||
key |= (suffixChar & 0x0F);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : MakeNode
|
||||
* Description: This routine creates and initializes a dictionary entry
|
||||
* for a string and the code word that encodes it.
|
||||
* Parameters : codeWord - code word used to encode the string prefixCode +
|
||||
* suffixChar
|
||||
* prefixCode - code for all but the last character of a
|
||||
* string.
|
||||
* suffixChar - the last character of a string
|
||||
* Effects : Node is allocated for new dictionary entry
|
||||
* Returned : Pointer to newly allocated node or NULL on error.
|
||||
* errno will be set on an error.
|
||||
***************************************************************************/
|
||||
static dict_node_t *
|
||||
MakeNode(const unsigned int codeWord, const unsigned int prefixCode, const unsigned char suffixChar)
|
||||
{
|
||||
dict_node_t *node;
|
||||
|
||||
node = malloc(sizeof(dict_node_t));
|
||||
|
||||
if (node != NULL) {
|
||||
node->codeWord = codeWord;
|
||||
node->prefixCode = prefixCode;
|
||||
node->suffixChar = suffixChar;
|
||||
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : FreeTree
|
||||
* Description: This routine will free all nodes of a tree rooted at the
|
||||
* node past as a parameter.
|
||||
* Parameters : node - root of tree to free
|
||||
* Effects : frees allocated tree node from initial parameter down.
|
||||
* Returned : none
|
||||
***************************************************************************/
|
||||
static void
|
||||
FreeTree(dict_node_t *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
/* nothing to free */
|
||||
return;
|
||||
|
||||
/* free left branch */
|
||||
if (node->left != NULL)
|
||||
FreeTree(node->left);
|
||||
|
||||
/* free right branch */
|
||||
if (node->right != NULL)
|
||||
FreeTree(node->right);
|
||||
|
||||
/* free root */
|
||||
free(node);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : FindDictionaryEntry
|
||||
* Description: This routine searches the dictionary tree for an entry
|
||||
* with a matching string (prefix code + suffix character).
|
||||
* If one isn't found, the parent node for that string is
|
||||
* returned.
|
||||
* Parameters : prefixCode - code for the prefix of string
|
||||
* c - last character in string
|
||||
* Effects : None
|
||||
* Returned : If string is in dictionary, pointer to node containing
|
||||
* string, otherwise pointer to suitable parent node. NULL
|
||||
* is returned for an empty tree.
|
||||
***************************************************************************/
|
||||
static dict_node_t *
|
||||
FindDictionaryEntry(dict_node_t *root, const int unsigned prefixCode, const unsigned char c)
|
||||
{
|
||||
unsigned int searchKey, key;
|
||||
|
||||
if (root == NULL)
|
||||
return NULL;
|
||||
|
||||
searchKey = MakeKey(prefixCode, c); /* key of string to find */
|
||||
|
||||
while (1) {
|
||||
/* key of current node */
|
||||
key = MakeKey(root->prefixCode, root->suffixChar);
|
||||
|
||||
if (key == searchKey)
|
||||
/* current node contains string */
|
||||
return root;
|
||||
else if (searchKey < key) {
|
||||
if (root->left != NULL)
|
||||
/* check left branch for string */
|
||||
root = root->left;
|
||||
else
|
||||
/* string isn't in tree, it can be added as a left child */
|
||||
return root;
|
||||
} else {
|
||||
if (root->right != NULL)
|
||||
/* check right branch for string */
|
||||
root = root->right;
|
||||
else
|
||||
/* string isn't in tree, it can be added as a right child */
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : PutCodeWord
|
||||
* Description: This function writes a code word from to an encoded file.
|
||||
* In order to deal with endian issue the code word is
|
||||
* written least significant byte followed by the remaining
|
||||
* bits.
|
||||
* Parameters : bfpOut - bit file containing the encoded data
|
||||
* code - code word to add to the encoded data
|
||||
* codeLen - length of the code word
|
||||
* Effects : code word is written to the encoded output
|
||||
* Returned : EOF for failure, ENOTSUP unsupported architecture,
|
||||
* otherwise the number of bits written. If an error occurs
|
||||
* after a partial write, the partially written bits will not
|
||||
* be unwritten.
|
||||
***************************************************************************/
|
||||
static int
|
||||
PutCodeWord(char *dest, int code)
|
||||
{
|
||||
static unsigned int realPos;
|
||||
int ret = 0;
|
||||
|
||||
if (bufPos >= 0x3000)
|
||||
ret = -1;
|
||||
else {
|
||||
realPos = bufPos >> 1;
|
||||
|
||||
if (bufPos & 1) {
|
||||
/* Odd position. */
|
||||
dest[realPos] = (dest[realPos] & 0x0f) | ((code << 4) & 0xf0);
|
||||
dest[realPos + 1] = (code >> 4) & 0xff;
|
||||
} else {
|
||||
/* Even position. */
|
||||
dest[realPos] = code & 0xff;
|
||||
dest[realPos + 1] = ((code >> 8) & 0x0f);
|
||||
}
|
||||
|
||||
bufPos += 3;
|
||||
|
||||
if (bufPos >= 0x3000)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
63
src/floppy/lzw/lzwlocal.h
Normal file
63
src/floppy/lzw/lzwlocal.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/***************************************************************************
|
||||
* Header for Lempel-Ziv-Welch Encoding and Decoding Library
|
||||
*
|
||||
* File : lzwlocal.h
|
||||
* Purpose : Provides constant definitions for functions values used within
|
||||
* the functions for Lempel-Ziv-Welch encoding/decoding.
|
||||
* Author : Michael Dipperstein
|
||||
* Date : February 22, 2015
|
||||
*
|
||||
****************************************************************************
|
||||
*
|
||||
* LZW: An ANSI C Lempel-Ziv-Welch Encoding/Decoding Routines
|
||||
* Copyright (C) 2015 by
|
||||
* Michael Dipperstein (mdipperstein@gmail.com)
|
||||
*
|
||||
* This file is part of the lzw library.
|
||||
*
|
||||
* The lzw 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The lzw 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _LZWLOCAL_H_
|
||||
#define _LZWLOCAL_H_
|
||||
/***************************************************************************
|
||||
* INCLUDED FILES
|
||||
***************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
/***************************************************************************
|
||||
* CONSTANTS
|
||||
***************************************************************************/
|
||||
#define MIN_CODE_LEN 12 /* min # bits in a code word */
|
||||
#define MAX_CODE_LEN 12 /* max # bits in a code word */
|
||||
|
||||
#define FIRST_CODE (1 << CHAR_BIT) /* value of 1st string code */
|
||||
#define MAX_CODES (1 << MAX_CODE_LEN)
|
||||
|
||||
#if (MIN_CODE_LEN <= CHAR_BIT)
|
||||
#error Code words must be larger than 1 character
|
||||
#endif
|
||||
|
||||
#if ((MAX_CODES - 1) > INT_MAX)
|
||||
#error There cannot be more codes than can fit in an integer
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
* MACROS
|
||||
***************************************************************************/
|
||||
#define CURRENT_MAX_CODES(bits) ((unsigned int)(1 << (bits)))
|
||||
|
||||
#endif /* ndef _LZWLOCAL_H_ */
|
Reference in New Issue
Block a user