123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- //
- // PAL DOS compress format (YJ_1) library
- //
- // Author: Lou Yihua <louyihua@21cn.com>
- //
- // Copyright 2006 - 2007 Lou Yihua
- //
- // This file is part of PAL library.
- //
- // 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, write to the Free Software
- // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- //
- // Ported to C from C++ and modified for compatibility with Big-Endian
- // by Wei Mingzhi <whistler@openoffice.org>.
- // TODO: fix YJ_2 for big-endian
- #include "common.h"
- #ifndef PAL_WIN95
- typedef struct _TreeNode
- {
- unsigned char value;
- unsigned char leaf;
- unsigned short level;
- unsigned int weight;
- struct _TreeNode *parent;
- struct _TreeNode *left;
- struct _TreeNode *right;
- } TreeNode;
- typedef struct _TreeNodeList
- {
- TreeNode *node;
- struct _TreeNodeList *next;
- } TreeNodeList;
- typedef struct _YJ_1_FILEHEADER
- {
- unsigned int Signature; // 'YJ_1'
- unsigned int UncompressedLength; // size before compression
- unsigned int CompressedLength; // size after compression
- unsigned short BlockCount; // number of blocks
- unsigned char Unknown;
- unsigned char HuffmanTreeLength; // length of huffman tree
- } YJ_1_FILEHEADER, *PYJ_1_FILEHEADER;
- typedef struct _YJ_1_BLOCKHEADER
- {
- unsigned short UncompressedLength; // maximum 0x4000
- unsigned short CompressedLength; // including the header
- unsigned short LZSSRepeatTable[4];
- unsigned char LZSSOffsetCodeLengthTable[4];
- unsigned char LZSSRepeatCodeLengthTable[3];
- unsigned char CodeCountCodeLengthTable[3];
- unsigned char CodeCountTable[2];
- } YJ_1_BLOCKHEADER, *PYJ_1_BLOCKHEADER;
- static unsigned int
- get_bits(
- const void *src,
- unsigned int *bitptr,
- unsigned int count
- )
- {
- unsigned char *temp = ((unsigned char *)src) + ((*bitptr >> 4) << 1);
- unsigned int bptr = *bitptr & 0xf;
- unsigned short mask;
- *bitptr += count;
- if (count > 16 - bptr)
- {
- count = count + bptr - 16;
- mask = 0xffff >> bptr;
- return (((temp[0] | (temp[1] << 8)) & mask) << count) | ((temp[2] | (temp[3] << 8)) >> (16 - count));
- }
- else
- return (((unsigned short)((temp[0] | (temp[1] << 8)) << bptr)) >> (16 - count));
- }
- static unsigned short
- get_loop(
- const void *src,
- unsigned int *bitptr,
- PYJ_1_BLOCKHEADER header
- )
- {
- if (get_bits(src, bitptr, 1))
- return header->CodeCountTable[0];
- else
- {
- unsigned int temp = get_bits(src, bitptr, 2);
- if (temp)
- return get_bits(src, bitptr, header->CodeCountCodeLengthTable[temp - 1]);
- else
- return header->CodeCountTable[1];
- }
- }
- static unsigned short
- get_count(
- const void *src,
- unsigned int *bitptr,
- PYJ_1_BLOCKHEADER header
- )
- {
- unsigned short temp;
- if ((temp = get_bits(src, bitptr, 2)) != 0)
- {
- if (get_bits(src, bitptr, 1))
- return get_bits(src, bitptr, header->LZSSRepeatCodeLengthTable[temp - 1]);
- else
- return SWAP16(header->LZSSRepeatTable[temp]);
- }
- else
- return SWAP16(header->LZSSRepeatTable[0]);
- }
- INT
- Decompress(
- LPCVOID Source,
- LPVOID Destination,
- INT DestSize
- )
- {
- PYJ_1_FILEHEADER hdr = (PYJ_1_FILEHEADER)Source;
- unsigned char *src = (unsigned char *)Source;
- unsigned char *dest;
- unsigned int i;
- TreeNode *root, *node;
- if (Source == NULL)
- return -1;
- if (SWAP32(hdr->Signature) != 0x315f4a59)
- return -1;
- if (SWAP32(hdr->UncompressedLength) > (unsigned int)DestSize)
- return -1;
- do
- {
- unsigned short tree_len = ((unsigned short)hdr->HuffmanTreeLength) * 2;
- unsigned int bitptr = 0;
- unsigned char *flag = (unsigned char *)src + 16 + tree_len;
- if ((node = root = (TreeNode *)malloc(sizeof(TreeNode) * (tree_len + 1))) == NULL)
- return -1;
- root[0].leaf = 0;
- root[0].value = 0;
- root[0].left = root + 1;
- root[0].right = root + 2;
- for (i = 1; i <= tree_len; i++)
- {
- root[i].leaf = !get_bits(flag, &bitptr, 1);
- root[i].value = src[15 + i];
- if (root[i].leaf)
- root[i].left = root[i].right = NULL;
- else
- {
- root[i].left = root + (root[i].value << 1) + 1;
- root[i].right = root[i].left + 1;
- }
- }
- src += 16 + tree_len + (((tree_len & 0xf) ? (tree_len >> 4) + 1 : (tree_len >> 4)) << 1);
- } while (0);
- dest = (unsigned char *)Destination;
- for (i = 0; i < SWAP16(hdr->BlockCount); i++)
- {
- unsigned int bitptr;
- PYJ_1_BLOCKHEADER header;
- header = (PYJ_1_BLOCKHEADER)src;
- src += 4;
- if (!SWAP16(header->CompressedLength))
- {
- unsigned short hul = SWAP16(header->UncompressedLength);
- while (hul--)
- {
- *dest++ = *src++;
- }
- continue;
- }
- src += 20;
- bitptr = 0;
- for (;;)
- {
- unsigned short loop;
- if ((loop = get_loop(src, &bitptr, header)) == 0)
- break;
- while (loop--)
- {
- node = root;
- for(; !node->leaf;)
- {
- if (get_bits(src, &bitptr, 1))
- node = node->right;
- else
- node = node->left;
- }
- *dest++ = node->value;
- }
- if ((loop = get_loop(src, &bitptr, header)) == 0)
- break;
- while (loop--)
- {
- unsigned int pos, count;
- count = get_count(src, &bitptr, header);
- pos = get_bits(src, &bitptr, 2);
- pos = get_bits(src, &bitptr, header->LZSSOffsetCodeLengthTable[pos]);
- while (count--)
- {
- *dest = *(dest - pos);
- dest++;
- }
- }
- }
- src = ((unsigned char *)header) + SWAP16(header->CompressedLength);
- }
- free(root);
- return SWAP32(hdr->UncompressedLength);
- }
- #else
- typedef struct _TreeNode
- {
- unsigned short weight;
- unsigned short value;
- struct _TreeNode* parent;
- struct _TreeNode* left;
- struct _TreeNode* right;
- } TreeNode;
- typedef struct _Tree
- {
- TreeNode* node;
- TreeNode** list;
- } Tree;
- static unsigned char data1[0x100] =
- {
- 0x3f,0x0b,0x17,0x03,0x2f,0x0a,0x16,0x00,0x2e,0x09,0x15,0x02,0x2d,0x01,0x08,0x00,
- 0x3e,0x07,0x14,0x03,0x2c,0x06,0x13,0x00,0x2b,0x05,0x12,0x02,0x2a,0x01,0x04,0x00,
- 0x3d,0x0b,0x11,0x03,0x29,0x0a,0x10,0x00,0x28,0x09,0x0f,0x02,0x27,0x01,0x08,0x00,
- 0x3c,0x07,0x0e,0x03,0x26,0x06,0x0d,0x00,0x25,0x05,0x0c,0x02,0x24,0x01,0x04,0x00,
- 0x3b,0x0b,0x17,0x03,0x23,0x0a,0x16,0x00,0x22,0x09,0x15,0x02,0x21,0x01,0x08,0x00,
- 0x3a,0x07,0x14,0x03,0x20,0x06,0x13,0x00,0x1f,0x05,0x12,0x02,0x1e,0x01,0x04,0x00,
- 0x39,0x0b,0x11,0x03,0x1d,0x0a,0x10,0x00,0x1c,0x09,0x0f,0x02,0x1b,0x01,0x08,0x00,
- 0x38,0x07,0x0e,0x03,0x1a,0x06,0x0d,0x00,0x19,0x05,0x0c,0x02,0x18,0x01,0x04,0x00,
- 0x37,0x0b,0x17,0x03,0x2f,0x0a,0x16,0x00,0x2e,0x09,0x15,0x02,0x2d,0x01,0x08,0x00,
- 0x36,0x07,0x14,0x03,0x2c,0x06,0x13,0x00,0x2b,0x05,0x12,0x02,0x2a,0x01,0x04,0x00,
- 0x35,0x0b,0x11,0x03,0x29,0x0a,0x10,0x00,0x28,0x09,0x0f,0x02,0x27,0x01,0x08,0x00,
- 0x34,0x07,0x0e,0x03,0x26,0x06,0x0d,0x00,0x25,0x05,0x0c,0x02,0x24,0x01,0x04,0x00,
- 0x33,0x0b,0x17,0x03,0x23,0x0a,0x16,0x00,0x22,0x09,0x15,0x02,0x21,0x01,0x08,0x00,
- 0x32,0x07,0x14,0x03,0x20,0x06,0x13,0x00,0x1f,0x05,0x12,0x02,0x1e,0x01,0x04,0x00,
- 0x31,0x0b,0x11,0x03,0x1d,0x0a,0x10,0x00,0x1c,0x09,0x0f,0x02,0x1b,0x01,0x08,0x00,
- 0x30,0x07,0x0e,0x03,0x1a,0x06,0x0d,0x00,0x19,0x05,0x0c,0x02,0x18,0x01,0x04,0x00
- };
- static unsigned char data2[0x10] =
- {
- 0x08,0x05,0x06,0x04,0x07,0x05,0x06,0x03,0x07,0x05,0x06,0x04,0x07,0x04,0x05,0x03
- };
- static void adjust_tree(Tree tree, unsigned short value)
- {
- TreeNode* node = tree.list[value];
- TreeNode tmp;
- TreeNode* tmp1;
- TreeNode* temp;
- while(node->value != 0x280)
- {
- temp = node + 1;
- while(node->weight == temp->weight)
- temp++;
- temp--;
- if (temp != node)
- {
- tmp1 = node->parent;
- node->parent = temp->parent;
- temp->parent = tmp1;
- if (node->value > 0x140)
- {
- node->left->parent = temp;
- node->right->parent = temp;
- }
- else
- tree.list[node->value] = temp;
- if (temp->value > 0x140)
- {
- temp->left->parent = node;
- temp->right->parent = node;
- }
- else
- tree.list[temp->value] = node;
- tmp = *node; *node = *temp; *temp = tmp;
- node = temp;
- }
- node->weight++;
- node = node->parent;
- }
- node->weight++;
- }
- static int build_tree(Tree *tree)
- {
- int i, ptr;
- TreeNode** list;
- TreeNode* node;
- if ((tree->list = list = (TreeNode **)malloc(sizeof(TreeNode*) * 321)) == NULL)
- return 0;
- if ((tree->node = node = (TreeNode *)malloc(sizeof(TreeNode) * 641)) == NULL)
- {
- free(list);
- return 0;
- }
- memset(list, 0, 321 * sizeof(TreeNode*));
- memset(node, 0, 641 * sizeof(TreeNode));
- for(i = 0; i <= 0x140; i++)
- list[i] = node + i;
- for(i = 0; i <= 0x280; i++)
- {
- node[i].value = i;
- node[i].weight = 1;
- }
- tree->node[0x280].parent = tree->node + 0x280;
- for(i = 0, ptr = 0x141; ptr <= 0x280; i += 2, ptr++)
- {
- node[ptr].left = node + i;
- node[ptr].right = node + i + 1;
- node[i].parent = node[i + 1].parent = node + ptr;
- node[ptr].weight = node[i].weight + node[i + 1].weight;
- }
- return 1;
- }
- #pragma pack(1)
- typedef struct _BitField
- {
- unsigned char b0: 1;
- unsigned char b1: 1;
- unsigned char b2: 1;
- unsigned char b3: 1;
- unsigned char b4: 1;
- unsigned char b5: 1;
- unsigned char b6: 1;
- unsigned char b7: 1;
- } BitField;
- #pragma pack()
- static int bt(const void* data, unsigned int pos)
- {
- BitField* bit = (BitField*)((unsigned char*)data + (pos >> 3));
- switch(pos & 0x7)
- {
- case 0: return bit->b0;
- case 1: return bit->b1;
- case 2: return bit->b2;
- case 3: return bit->b3;
- case 4: return bit->b4;
- case 5: return bit->b5;
- case 6: return bit->b6;
- case 7: return bit->b7;
- }
- return 0;
- }
- static void bit(void* data, unsigned int pos, int set)
- {
- BitField* bit = (BitField*)((unsigned char*)data + (pos >> 3));
- switch(pos & 0x7)
- {
- case 0:
- bit->b0 = set;
- break;
- case 1:
- bit->b1 = set;
- break;
- case 2:
- bit->b2 = set;
- break;
- case 3:
- bit->b3 = set;
- break;
- case 4:
- bit->b4 = set;
- break;
- case 5:
- bit->b5 = set;
- break;
- case 6:
- bit->b6 = set;
- break;
- case 7:
- bit->b7 = set;
- break;
- }
- }
- INT
- Decompress(
- LPCVOID Source,
- LPVOID Destination,
- INT DestSize
- )
- {
- unsigned int len = 0, ptr = 0, Length = 0;
- unsigned char* src = (unsigned char*)Source + 4;
- unsigned char* dest;
- Tree tree;
- TreeNode* node;
- if (Source == NULL)
- return -1;
- if (!build_tree(&tree))
- return -1;
- Length = SWAP32(*((unsigned int*)Source));
- if (Length > DestSize)
- return -1;
- dest = (unsigned char*)Destination;
- while (1)
- {
- unsigned short val;
- node = tree.node + 0x280;
- while(node->value > 0x140)
- {
- if (bt(src, ptr))
- node = node->right;
- else
- node = node->left;
- ptr++;
- }
- val = node->value;
- if (tree.node[0x280].weight == 0x8000)
- {
- int i;
- for(i = 0; i < 0x141; i++)
- if (tree.list[i]->weight & 0x1)
- adjust_tree(tree, i);
- for(i = 0; i <= 0x280; i++)
- tree.node[i].weight >>= 1;
- }
- adjust_tree(tree, val);
- if (val > 0xff)
- {
- int i;
- unsigned int temp, tmp, pos;
- unsigned char* pre;
- for(i = 0, temp = 0; i < 8; i++, ptr++)
- temp |= (unsigned int)bt(src, ptr) << i;
- tmp = temp & 0xff;
- for(; i < data2[tmp & 0xf] + 6; i++, ptr++)
- temp |= (unsigned int)bt(src, ptr) << i;
- temp >>= data2[tmp & 0xf];
- pos = (temp & 0x3f) | ((unsigned int)data1[tmp] << 6);
- if (pos == 0xfff)
- break;
- pre = dest - pos - 1;
- for(i = 0; i < val - 0xfd; i++)
- *dest++ = *pre++;
- len += val - 0xfd;
- }
- else
- {
- *dest++ = (unsigned char)val;
- len++;
- }
- }
- free(tree.list);
- free(tree.node);
- return Length;
- }
- #endif
|