Update to v080r04 release.

byuu says:

Adds nall/inflate.hpp and nall/unzip.hpp. Updates nall/resource.hpp to
encode and decode using ZIP/deflate files, rather than a much simpler
(and less powerful) LZSS implementation. Cuts the bsnes-logo.hpp file
from 270KB to 130KB, and the binary overhead from 80KB to 35KB.
This commit is contained in:
Tim Allen 2011-07-24 23:51:01 +10:00
parent 8276700381
commit f38af85e0a
12 changed files with 1901 additions and 2692 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +0,0 @@
#ifndef NALL_DICTIONARY_HPP
#define NALL_DICTIONARY_HPP
#include <nall/array.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
namespace nall {
class dictionary {
public:
string operator[](const char *input) {
for(unsigned i = 0; i < index_input.size(); i++) {
if(index_input[i] == input) return index_output[i];
}
//no match, use input; remove input identifier, if one exists
if(strbegin(input, "{{")) {
if(auto pos = strpos(input, "}}")) {
string temp = substr(input, pos() + 2);
return temp;
}
}
return input;
}
bool import(const char *filename) {
string data;
if(data.readfile(filename) == false) return false;
data.ltrim<1>("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
data.replace("\r", "");
lstring line;
line.split("\n", data);
for(unsigned i = 0; i < line.size(); i++) {
lstring part;
//format: "Input" = "Output"
part.qsplit("=", line[i]);
if(part.size() != 2) continue;
//remove whitespace
part[0].trim();
part[1].trim();
//remove quotes
part[0].trim<1>("\"");
part[1].trim<1>("\"");
unsigned n = index_input.size();
index_input[n] = part[0];
index_output[n] = part[1];
}
return true;
}
void reset() {
index_input.reset();
index_output.reset();
}
~dictionary() {
reset();
}
dictionary& operator=(const dictionary&) = delete;
dictionary(const dictionary&) = delete;
protected:
lstring index_input;
lstring index_output;
};
}
#endif

169
bsnes/nall/http.hpp Executable file
View File

@ -0,0 +1,169 @@
#ifndef NALL_HTTP_HPP
#define NALL_HTTP_HPP
#if !defined(_WIN32)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#else
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <nall/platform.hpp>
#include <nall/string.hpp>
namespace nall {
struct http {
string hostname;
addrinfo *serverinfo;
int serversocket;
string header;
inline void download(const string &path, uint8_t *&data, unsigned &size) {
data = 0;
size = 0;
send({
"GET ", path, " HTTP/1.1\n"
"Host: ", hostname, "\n"
"\n"
});
header = downloadHeader();
downloadContent(data, size);
}
inline bool connect(string host, unsigned port) {
hostname = host;
addrinfo hints;
memset(&hints, 0, sizeof(addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int status = getaddrinfo(hostname, string(port), &hints, &serverinfo);
if(status != 0) return false;
serversocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);
if(serversocket == -1) return false;
int result = ::connect(serversocket, serverinfo->ai_addr, serverinfo->ai_addrlen);
if(result == -1) return false;
return true;
}
inline bool send(const string &data) {
return send((const uint8_t*)(const char*)data, data.length());
}
inline bool send(const uint8_t *data, unsigned size) {
while(size) {
int length = ::send(serversocket, data, size, 0);
if(length == -1) return false;
data += length;
size -= length;
}
return true;
}
inline string downloadHeader() {
string output;
do {
char buffer[2];
int length = recv(serversocket, buffer, 1, 0);
if(length <= 0) return output;
buffer[1] = 0;
output.append(buffer);
} while(output.endswith("\r\n\r\n") == false);
return output;
}
inline string downloadChunkLength() {
string output;
do {
char buffer[2];
int length = recv(serversocket, buffer, 1, 0);
if(length <= 0) return output;
buffer[1] = 0;
output.append(buffer);
} while(output.endswith("\r\n") == false);
return output;
}
inline void downloadContent(uint8_t *&data, unsigned &size) {
unsigned capacity = 0;
if(header.position("Transfer-Encoding: chunked")) {
while(true) {
unsigned length = hex(downloadChunkLength());
if(length == 0) break;
capacity += length;
data = (uint8_t*)realloc(data, capacity);
char buffer[length];
while(length) {
int packetlength = recv(serversocket, buffer, length, 0);
if(packetlength <= 0) break;
memcpy(data + size, buffer, packetlength);
size += packetlength;
length -= packetlength;
}
}
} else if(auto position = header.position("Content-Length: ")) {
unsigned length = decimal((const char*)header + position() + 16);
while(length) {
char buffer[256];
int packetlength = recv(serversocket, buffer, min(256, length), 0);
if(packetlength <= 0) break;
capacity += packetlength;
data = (uint8_t*)realloc(data, capacity);
memcpy(data + size, buffer, packetlength);
size += packetlength;
length -= packetlength;
}
} else {
while(true) {
char buffer[256];
int packetlength = recv(serversocket, buffer, 256, 0);
if(packetlength <= 0) break;
capacity += packetlength;
data = (uint8_t*)realloc(data, capacity);
memcpy(data + size, buffer, packetlength);
size += packetlength;
}
}
data = (uint8_t*)realloc(data, capacity + 1);
data[capacity] = 0;
}
inline void disconnect() {
close(serversocket);
freeaddrinfo(serverinfo);
serverinfo = 0;
serversocket = -1;
}
inline http() {
#ifdef _WIN32
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock == INVALID_SOCKET && WSAGetLastError() == WSANOTINITIALISED) {
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
WSACleanup();
return;
}
} else close(sock);
#endif
}
};
}
#endif

357
bsnes/nall/inflate.hpp Executable file
View File

@ -0,0 +1,357 @@
#ifndef NALL_INFLATE_HPP
#define NALL_INFLATE_HPP
#include <setjmp.h>
namespace nall {
namespace puff {
inline int puff(
unsigned char *dest, unsigned long *destlen,
unsigned char *source, unsigned long *sourcelen
);
}
inline bool inflate(
uint8_t *target, unsigned targetLength,
const uint8_t *source, unsigned sourceLength
) {
unsigned long tl = targetLength, sl = sourceLength;
return puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl) == 0;
}
namespace puff {
//zlib/contrib/puff.c
//version 2.1*
//author: Mark Adler
//license: zlib
//ported by: byuu
//* I have corrected a bug in fixed(), where it was accessing uninitialized
// memory: calling construct() with lencode prior to initializing lencode.count
enum {
MAXBITS = 15,
MAXLCODES = 286,
MAXDCODES = 30,
FIXLCODES = 288,
MAXCODES = MAXLCODES + MAXDCODES,
};
struct state {
unsigned char *out;
unsigned long outlen;
unsigned long outcnt;
unsigned char *in;
unsigned long inlen;
unsigned long incnt;
int bitbuf;
int bitcnt;
jmp_buf env;
};
struct huffman {
short *count;
short *symbol;
};
inline int bits(state *s, int need) {
long val;
val = s->bitbuf;
while(s->bitcnt < need) {
if(s->incnt == s->inlen) longjmp(s->env, 1);
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
s->bitcnt += 8;
}
s->bitbuf = (int)(val >> need);
s->bitcnt -= need;
return (int)(val & ((1L << need) - 1));
}
inline int stored(state *s) {
unsigned len;
s->bitbuf = 0;
s->bitcnt = 0;
if(s->incnt + 4 > s->inlen) return 2;
len = s->in[s->incnt++];
len |= s->in[s->incnt++] << 8;
if(s->in[s->incnt++] != (~len & 0xff) ||
s->in[s->incnt++] != ((~len >> 8) & 0xff)
) return 2;
if(s->incnt + len > s->inlen) return 2;
if(s->out != 0) {
if(s->outcnt + len > s->outlen) return 1;
while(len--) s->out[s->outcnt++] = s->in[s->incnt++];
} else {
s->outcnt += len;
s->incnt += len;
}
return 0;
}
inline int decode(state *s, huffman *h) {
int len, code, first, count, index, bitbuf, left;
short *next;
bitbuf = s->bitbuf;
left = s->bitcnt;
code = first = index = 0;
len = 1;
next = h->count + 1;
while(true) {
while(left--) {
code |= bitbuf & 1;
bitbuf >>= 1;
count = *next++;
if(code - count < first) {
s->bitbuf = bitbuf;
s->bitcnt = (s->bitcnt - len) & 7;
return h->symbol[index + (code - first)];
}
index += count;
first += count;
first <<= 1;
code <<= 1;
len++;
}
left = (MAXBITS + 1) - len;
if(left == 0) break;
if(s->incnt == s->inlen) longjmp(s->env, 1);
bitbuf = s->in[s->incnt++];
if(left > 8) left = 8;
}
return -10;
}
inline int construct(huffman *h, short *length, int n) {
int symbol, len, left;
short offs[MAXBITS + 1];
for(len = 0; len <= MAXBITS; len++) h->count[len] = 0;
for(symbol = 0; symbol < n; symbol++) h->count[length[symbol]]++;
if(h->count[0] == n) return 0;
left = 1;
for(len = 1; len <= MAXBITS; len++) {
left <<= 1;
left -= h->count[len];
if(left < 0) return left;
}
offs[1] = 0;
for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len];
for(symbol = 0; symbol < n; symbol++) {
if(length[symbol] != 0) h->symbol[offs[length[symbol]]++] = symbol;
}
return left;
}
inline int codes(state *s, huffman *lencode, huffman *distcode) {
int symbol, len;
unsigned dist;
static const short lens[29] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
};
static const short lext[29] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
};
static const short dists[30] = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577
};
static const short dext[30] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13
};
do {
symbol = decode(s, lencode);
if(symbol < 0) return symbol;
if(symbol < 256) {
if(s->out != 0) {
if(s->outcnt == s->outlen) return 1;
s->out[s->outcnt] = symbol;
}
s->outcnt++;
} else if(symbol > 256) {
symbol -= 257;
if(symbol >= 29) return -10;
len = lens[symbol] + bits(s, lext[symbol]);
symbol = decode(s, distcode);
if(symbol < 0) return symbol;
dist = dists[symbol] + bits(s, dext[symbol]);
#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
if(dist > s->outcnt) return -11;
#endif
if(s->out != 0) {
if(s->outcnt + len > s->outlen) return 1;
while(len--) {
s->out[s->outcnt] =
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
dist > s->outcnt ? 0 :
#endif
s->out[s->outcnt - dist];
s->outcnt++;
}
} else {
s->outcnt += len;
}
}
} while(symbol != 256);
return 0;
}
inline int fixed(state *s) {
static int virgin = 1;
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
static huffman lencode, distcode;
if(virgin) {
int symbol = 0;
short lengths[FIXLCODES];
lencode.count = lencnt;
lencode.symbol = lensym;
distcode.count = distcnt;
distcode.symbol = distsym;
for(; symbol < 144; symbol++) lengths[symbol] = 8;
for(; symbol < 256; symbol++) lengths[symbol] = 9;
for(; symbol < 280; symbol++) lengths[symbol] = 7;
for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
construct(&lencode, lengths, FIXLCODES);
for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
construct(&distcode, lengths, MAXDCODES);
virgin = 0;
}
return codes(s, &lencode, &distcode);
}
inline int dynamic(state *s) {
int nlen, ndist, ncode, index, err;
short lengths[MAXCODES];
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
short distcnt[MAXBITS + 1], distsym[MAXDCODES];
huffman lencode, distcode;
static const short order[19] = {
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
lencode.count = lencnt;
lencode.symbol = lensym;
distcode.count = distcnt;
distcode.symbol = distsym;
nlen = bits(s, 5) + 257;
ndist = bits(s, 5) + 1;
ncode = bits(s, 4) + 4;
if(nlen > MAXLCODES || ndist > MAXDCODES) return -3;
for(index = 0; index < ncode; index++) lengths[order[index]] = bits(s, 3);
for(; index < 19; index++) lengths[order[index]] = 0;
err = construct(&lencode, lengths, 19);
if(err != 0) return -4;
index = 0;
while(index < nlen + ndist) {
int symbol, len;
symbol = decode(s, &lencode);
if(symbol < 16) {
lengths[index++] = symbol;
} else {
len = 0;
if(symbol == 16) {
if(index == 0) return -5;
len = lengths[index - 1];
symbol = 3 + bits(s, 2);
} else if(symbol == 17) {
symbol = 3 + bits(s, 3);
} else {
symbol = 11 + bits(s, 7);
}
if(index + symbol > nlen + ndist) return -6;
while(symbol--) lengths[index++] = len;
}
}
if(lengths[256] == 0) return -9;
err = construct(&lencode, lengths, nlen);
if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) return -7;
err = construct(&distcode, lengths + nlen, ndist);
if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) return -8;
return codes(s, &lencode, &distcode);
}
inline int puff(
unsigned char *dest, unsigned long *destlen,
unsigned char *source, unsigned long *sourcelen
) {
state s;
int last, type, err;
s.out = dest;
s.outlen = *destlen;
s.outcnt = 0;
s.in = source;
s.inlen = *sourcelen;
s.incnt = 0;
s.bitbuf = 0;
s.bitcnt = 0;
if(setjmp(s.env) != 0) {
err = 2;
} else {
do {
last = bits(&s, 1);
type = bits(&s, 2);
err = type == 0 ? stored(&s)
: type == 1 ? fixed(&s)
: type == 2 ? dynamic(&s)
: -1;
if(err != 0) break;
} while(!last);
}
if(err <= 0) {
*destlen = s.outcnt;
*sourcelen = s.incnt;
}
return err;
}
}
}
#endif

View File

@ -67,6 +67,7 @@
#define rmdir _rmdir
#define usleep(n) Sleep(n / 1000)
#define vsnprintf _vsnprintf
static int close(int sock) { return closesocket(sock); }
#endif
//================

View File

@ -2,30 +2,26 @@
#define NALL_RESOURCE_HPP
#include <nall/file.hpp>
#include <nall/lzss.hpp>
#include <nall/unzip.hpp>
namespace nall {
struct resource {
//create resource with "zip -9 resource.zip resource"
static bool encode(const char *outputFilename, const char *inputFilename) {
file fp;
if(fp.open(inputFilename, file::mode::read) == false) return false;
unsigned inputSize = fp.size();
uint8_t *inputData = new uint8_t[inputSize];
fp.read(inputData, inputSize);
unsigned size = fp.size();
uint8_t *data = new uint8_t[size];
fp.read(data, size);
fp.close();
unsigned outputSize;
uint8_t *outputData;
lzss::encode(outputData, outputSize, inputData, inputSize);
fp.open(outputFilename, file::mode::write);
fp.print("static const unsigned size = ", inputSize, ";\n");
fp.print("static const uint8_t data[", outputSize, "] = {\n");
uint8_t *p = outputData;
while(outputSize) {
fp.print("static const uint8_t data[", size, "] = {\n");
uint8_t *p = data;
while(size) {
fp.print(" ");
for(unsigned n = 0; n < 32 && outputSize; n++, outputSize--) {
for(unsigned n = 0; n < 32 && size; n++, size--) {
fp.print((unsigned)*p++, ",");
}
fp.print("\n");
@ -33,17 +29,23 @@ struct resource {
fp.print("};\n");
fp.close();
delete[] inputData;
delete[] outputData;
delete[] data;
}
uint8_t *data;
unsigned size;
bool decode(const uint8_t *inputData, unsigned outputSize) {
//extract first file from ZIP archive
bool decode(const uint8_t *cdata, unsigned csize) {
if(data) delete[] data;
lzss::decode(data, inputData, size = outputSize);
return true;
unzip archive;
if(archive.open(cdata, csize) == false) return false;
if(archive.file.size() == 0) return false;
bool result = archive.extract(archive.file[0], data, size);
archive.close();
return result;
}
resource() : data(0), size(0) {

View File

@ -1 +0,0 @@
g++-4.5 -std=gnu++0x -O3 -fomit-frame-pointer -s -o test test.cpp -I../..

View File

@ -1,44 +0,0 @@
#include <nall/any.hpp>
#include <nall/array.hpp>
#include <nall/base64.hpp>
#include <nall/concept.hpp>
#include <nall/config.hpp>
#include <nall/dictionary.hpp>
#include <nall/directory.hpp>
#include <nall/dl.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/foreach.hpp>
#include <nall/function.hpp>
#include <nall/input.hpp>
#include <nall/lzss.hpp>
#include <nall/priorityqueue.hpp>
#include <nall/public_cast.hpp>
#include <nall/reference_array.hpp>
#include <nall/resource.hpp>
#include <nall/serializer.hpp>
#include <nall/stack.hpp>
#include <nall/static.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>
#include <nall/snes/cpu.hpp>
#include <nall/snes/smp.hpp>
#include <nall/snes/cartridge.hpp>
#include <nall/gameboy/cartridge.hpp>
using namespace nall;
#include "bsnes-logo.hpp"
int main(int argc, char **argv) {
// resource::encode("bsnes-logo.hpp", "bsnes-logo.bmp");
resource logo;
logo.decode(data, size);
file fp;
fp.open("output.bmp", file::mode::write);
fp.write(logo.data, logo.size);
fp.close();
return 0;
}

124
bsnes/nall/unzip.hpp Executable file
View File

@ -0,0 +1,124 @@
#ifndef NALL_UNZIP_HPP
#define NALL_UNZIP_HPP
#include <nall/filemap.hpp>
#include <nall/inflate.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
namespace nall {
struct unzip {
struct File {
string name;
const uint8_t *data;
unsigned size;
unsigned csize;
unsigned cmode; //0 = uncompressed, 8 = deflate
unsigned crc32;
};
inline bool open(const char *filename) {
close();
if(fm.open(filename, filemap::mode::read) == false) return false;
if(open(fm.data(), fm.size()) == false) {
fm.close();
return false;
}
return true;
}
inline bool open(const uint8_t *data, unsigned size) {
if(size < 22) return false;
filedata = data;
filesize = size;
file.reset();
const uint8_t *footer = data + size - 22;
const uint8_t *directory = data + read(footer + 16, 4);
while(true) {
unsigned signature = read(directory + 0, 4);
if(signature != 0x02014b50) break;
File file;
file.cmode = read(directory + 10, 2);
file.crc32 = read(directory + 16, 4);
file.csize = read(directory + 20, 4);
file.size = read(directory + 24, 4);
unsigned namelength = read(directory + 28, 2);
unsigned extralength = read(directory + 30, 2);
unsigned commentlength = read(directory + 32, 2);
char *filename = new char[namelength + 1];
memcpy(filename, directory + 46, namelength);
filename[namelength] = 0;
file.name = filename;
delete[] filename;
unsigned offset = read(directory + 42, 4);
unsigned offsetNL = read(data + offset + 26, 2);
unsigned offsetEL = read(data + offset + 28, 2);
file.data = data + offset + 30 + offsetNL + offsetEL;
directory += 46 + namelength + extralength + commentlength;
this->file.append(file);
}
return true;
}
inline bool extract(File &file, uint8_t *&data, unsigned &size) {
data = 0, size = 0;
if(file.cmode == 0) {
size = file.size;
data = new uint8_t[size];
memcpy(data, file.data, size);
return true;
}
if(file.cmode == 8) {
size = file.size;
data = new uint8_t[size];
if(inflate(data, size, file.data, file.csize) == false) {
delete[] data;
size = 0;
return false;
}
return true;
}
return false;
}
inline void close() {
if(fm.open()) fm.close();
}
~unzip() {
close();
}
protected:
filemap fm;
const uint8_t *filedata;
unsigned filesize;
unsigned read(const uint8_t *data, unsigned size) {
unsigned result = 0, shift = 0;
while(size--) { result |= *data++ << shift; shift += 8; }
return result;
}
public:
linear_vector<File> file;
};
}
#endif

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "080.03";
static const char Version[] = "080.04";
static const unsigned SerializerVersion = 21;
}
}

View File

@ -12,6 +12,7 @@ synchronize "phoenix"
test -d libco/doc && rm -r libco/doc
test -d libco/test && rm -r libco/test
test -d nall/test && rm -r nall/test
test -d ruby/_test && rm -r ruby/_test
test -d phoenix/nall && rm -r phoenix/nall
test -d phoenix/test && rm -r phoenix/test

View File

@ -23,7 +23,7 @@ void AboutWindow::create() {
}
void AboutWindow::show() {
logo.decode(bsnesLogoData, bsnesLogoSize);
logo.decode(bsnesLogoData, sizeof bsnesLogoData);
setVisible();
uint32_t *buffer = canvas.buffer();
for(unsigned y = 0; y < 180; y++) {