Index: rockbox/apps/plugins/viewers.config =================================================================== --- rockbox/apps/plugins/viewers.config (revision 14450) +++ rockbox/apps/plugins/viewers.config (working copy) @@ -25,6 +25,7 @@ wav,viewers/wavplay,9 wav,viewers/wavview,10 wav,viewers/test_codec,- +wwi,viewers/mww,- bmp,apps/rockpaint,11 mpg,viewers/mpegplayer,4 mpeg,viewers/mpegplayer,4 Index: rockbox/apps/plugins/mww/mwdb.h =================================================================== --- rockbox/apps/plugins/mww/mwdb.h (revision 0) +++ rockbox/apps/plugins/mww/mwdb.h (revision 0) @@ -0,0 +1,28 @@ +#ifndef MWDB_H +#define MWDB_H +#include +#ifdef SIMULATOR +#define printsim printf +#else +#define printsim(...) +#endif + +int mwdb_findarticle(const char* filename, + char* artnme, + uint16_t artnmelen, + uint32_t *res_lo, + uint32_t *res_hi, + bool progress, + bool promptname, + bool casesense + ); + +int mwdb_loadarticle(const char * filename, + void * scratchmem, + void * articlemem, + uint32_t articlememlen, + uint32_t *articlelen, + uint32_t res_lo, + uint32_t res_hi); + +#endif Index: rockbox/apps/plugins/mww/mallocer.c =================================================================== --- rockbox/apps/plugins/mww/mallocer.c (revision 0) +++ rockbox/apps/plugins/mww/mallocer.c (revision 0) @@ -0,0 +1,90 @@ +/*Based on the malloc in codeclib*/ +#include "mallocer.h" +unsigned char* mallocbuf[MEMPOOL_MAX]; +long mem_ptr[MEMPOOL_MAX]; +size_t bufsize[MEMPOOL_MAX]; +#ifdef DBWPWM +long maxreq[MEMPOOL_MAX]; +#endif +#ifdef INROCKBOX +#include "plugin.h" +struct plugin_api *local_rb; +int wpw_init_mempool(struct plugin_api* rb,unsigned char mempool) +{ + local_rb = rb; + mem_ptr[mempool] = 0; + mallocbuf[mempool] = (unsigned char *)rb->plugin_get_buffer(&bufsize[mempool]); + return 0; +} +int wpw_init_mempool_pdm(struct plugin_api* rb,unsigned char mempool, unsigned char* mem,long memsize) +{ + local_rb = rb; + mem_ptr[mempool] = 0; + mallocbuf[mempool] = mem; + bufsize[mempool]=memsize; + return 0; +} +#else +void wpw_init_mempool(unsigned char mempool,unsigned char* mem,long memsize) +{ + mem_ptr[mempool] = 0; + mallocbuf[mempool] = mem; + bufsize[mempool]=memsize; +} +#endif +void wpw_reset_mempool(unsigned char mempool){ + mem_ptr[mempool]=0; +} +void wpw_destroy_mempool(unsigned char mempool){ + mem_ptr[mempool] = 0; + mallocbuf[mempool] =0; + bufsize[mempool]=0; +} +long wpw_available(unsigned char mempool){ + return bufsize[mempool]-mem_ptr[mempool]; +} + +void* wpw_malloc(unsigned char mempool,size_t size) +{ + void* x; +#ifdef DBWPWM + if( mem_ptr[mempool] + size>maxreq[mempool]) + maxreq[mempool]=mem_ptr[mempool] + (long)size; + printf("Req[%d]:%d<%d (%d,%d)\n",mempool,mem_ptr[mempool] + (long)size, bufsize[mempool],bufsize[mempool] - mem_ptr[mempool] - (long)size ,maxreq[mempool]); +#endif + if (mem_ptr[mempool] + size > bufsize[mempool] ){ + return NULL; + } + + x=&mallocbuf[mempool][mem_ptr[mempool]]; + mem_ptr[mempool]+=(size+3)&~3; /* Keep memory 32-bit aligned */ + //printf("%d,%d,(%d)\n",x,mallocbuf[mempool][mem_ptr[mempool]],mallocbuf[mempool][mem_ptr[mempool]]-x); + return(x); +} + +void* wpw_calloc(unsigned char mempool,size_t nmemb, size_t size) +{ + void* x; + x = wpw_malloc(mempool,nmemb*size); + if (x == NULL) + return NULL; +#ifdef INROCKBOX + local_rb->memset(x,0,nmemb*size); +#else + memset(x,0,nmemb*size); +#endif + return(x); +} + +void codec_free(unsigned char mempool,void* ptr) { + (void)ptr; + (void)mempool; +} + +void* wpw_realloc(unsigned char mempool,void* ptr, size_t size) +{ + void* x; + (void)ptr; + x = wpw_malloc(mempool,size); + return(x); +} Index: rockbox/apps/plugins/mww/btsearch.h =================================================================== --- rockbox/apps/plugins/mww/btsearch.h (revision 0) +++ rockbox/apps/plugins/mww/btsearch.h (revision 0) @@ -0,0 +1,10 @@ +#ifndef BTSEARCH_H +#define BTSEARCH_H +#include +extern struct plugin_api *rb; +#define memset rb->memset +#define memcpy rb->memcpy +#define read rb->read +#define utf8decode rb->utf8decode +void search_btree(int fp,const char* key,uint16_t rkeylen, uint32_t globoffs, uint32_t* res_lo,uint32_t* res_hi,const bool casesense); +#endif Index: rockbox/apps/plugins/mww/bbfuncs.c =================================================================== --- rockbox/apps/plugins/mww/bbfuncs.c (revision 0) +++ rockbox/apps/plugins/mww/bbfuncs.c (revision 0) @@ -0,0 +1,226 @@ +#define INROCKBOX +#include "plugin.h" +extern struct plugin_api *rb; +#define read rb->read +#define write rb->write +const uint32_t crc_table[256]= {0,1996959894,-301047508,-1727442502,124634137,1886057615, + -379345611,-1637575261,249268274,2044508324,-522852066, + -1747789432,162941995,2125561021,-407360249,-1866523247, + 498536548,1789927666,-205950648,-2067906082,450548861, + 1843258603,-187386543,-2083289657,325883990,1684777152, + -43845254,-1973040660,335633487,1661365465,-99664541, + -1928851979,997073096,1281953886,-715111964,-1570279054, + 1006888145,1258607687,-770865667,-1526024853,901097722, + 1119000684,-608450090,-1396901568,853044451,1172266101, + -589951537,-1412350631,651767980,1373503546,-925412992, + -1076862698,565507253,1454621731,-809855591,-1195530993, + 671266974,1594198024,-972236366,-1324619484,795835527, + 1483230225,-1050600021,-1234817731,1994146192,31158534, + -1731059524,-271249366,1907459465,112637215,-1614814043, + -390540237,2013776290,251722036,-1777751922,-519137256, + 2137656763,141376813,-1855689577,-429695999,1802195444, + 476864866,-2056965928,-228458418,1812370925,453092731, + -2113342271,-183516073,1706088902,314042704,-1950435094, + -54949764,1658658271,366619977,-1932296973,-69972891, + 1303535960,984961486,-1547960204,-725929758,1256170817, + 1037604311,-1529756563,-740887301,1131014506,879679996, + -1385723834,-631195440,1141124467,855842277,-1442165665, + -586318647,1342533948,654459306,-1106571248,-921952122, + 1466479909,544179635,-1184443383,-832445281,1591671054, + 702138776,-1328506846,-942167884,1504918807,783551873, + -1212326853,-1061524307,-306674912,-1698712650,62317068, + 1957810842,-355121351,-1647151185,81470997,1943803523, + -480048366,-1805370492,225274430,2053790376,-468791541, + -1828061283,167816743,2097651377,-267414716,-2029476910, + 503444072,1762050814,-144550051,-2140837941,426522225, + 1852507879,-19653770,-1982649376,282753626,1742555852, + -105259153,-1900089351,397917763,1622183637,-690576408, + -1580100738,953729732,1340076626,-776247311,-1497606297, + 1068828381,1219638859,-670225446,-1358292148,906185462, + 1090812512,-547295293,-1469587627,829329135,1181335161, + -882789492,-1134132454,628085408,1382605366,-871598187, + -1156888829,570562233,1426400815,-977650754,-1296233688, + 733239954,1555261956,-1026031705,-1244606671,752459403, + 1541320221,-1687895376,-328994266,1969922972,40735498, + -1677130071,-351390145,1913087877,83908371,-1782625662, + -491226604,2075208622,213261112,-1831694693,-438977011, + 2094854071,198958881,-2032938284,-237706686,1759359992, + 534414190,-2118248755,-155638181,1873836001,414664567, + -2012718362,-15766928,1711684554,285281116,-1889165569, + -127750551,1634467795,376229701,-1609899400,-686959890, + 1308918612,956543938,-1486412191,-799009033,1231636301, + 1047427035,-1362007478,-640263460,1088359270,936918000, + -1447252397,-558129467,1202900863,817233897,-1111625188, + -893730166,1404277552,615818150,-1160759803,-841546093, + 1423857449,601450431,-1285129682,-1000256840,1567103746, + 711928724,-1274298825,-1022587231,1510334235,755167117}; + + +void error_die(const char* msg){ +#ifndef INROCKBOX + printf("%s\n",msg); + exit(0); +#else + (void)msg; +#endif + //FIXME:Cause plugin to die +} +void error_msg(const char* msg){ +#ifndef INROCKBOX + printf("%s\n",msg); +#else + (void)msg; +#endif +} + +size_t safe_read(int fd, void *buf, size_t count) +{ + ssize_t n; + + do { + n = read(fd, buf, count); + } while (n < 0&&n!=-1); + + return n; +} + +/* + * Read all of the supplied buffer from a file + * This does multiple reads as necessary. + * Returns the amount read, or -1 on an error. + * A short read is returned on an end of file. + */ +ssize_t full_read(int fd, void *buf, size_t len) +{ + ssize_t cc; + ssize_t total; + + total = 0; + + while (len) { + cc = safe_read(fd, buf, len); + + if (cc < 0) + return cc; /* read() returns -1 on failure. */ + + if (cc == 0) + break; + + buf = ((char *)buf) + cc; + total += cc; + len -= cc; + } + + return total; +} + +// Die with an error message if we can't read the entire buffer. +void xread(int fd, void *buf, ssize_t count) +{ + if (count) { + ssize_t size = full_read(fd, buf, count); + if (size != count) + error_die("short read"); + } +} + +// Die with an error message if we can't read one character. +unsigned char xread_char(int fd) +{ + char tmp; + + xread(fd, &tmp, 1); + + return tmp; +} + +ssize_t safe_write(int fd, const void *buf, size_t count) +{ + ssize_t n; + + do { + n = write(fd, buf, count); + } while (n < 0); + + return n; +} + +/* + * Write all of the supplied buffer out to a file. + * This does multiple writes as necessary. + * Returns the amount written, or -1 on an error. + */ +ssize_t full_write(int fd, const void *buf, size_t len) +{ + ssize_t cc; + ssize_t total; + + total = 0; + + while (len) { + cc = safe_write(fd, buf, len); + + if (cc < 0) + return cc; /* write() returns -1 on failure. */ + + total += cc; + buf = ((const char *)buf) + cc; + len -= cc; + } + + return total; +} +void check_header_gzip(int src_fd) +{ + union { + unsigned char raw[8]; + struct { + unsigned char method; + unsigned char flags; + unsigned int mtime; + unsigned char xtra_flags; + unsigned char os_flags; + } formatted; + } header; + + xread(src_fd, header.raw, 8); + + /* Check the compression method */ + if (header.formatted.method != 8) { +/* error_die("Unknown compression method %d", + header.formatted.method);*/ + error_die("Unknown compression method"); + } + + if (header.formatted.flags & 0x04) { + /* bit 2 set: extra field present */ + unsigned char extra_short; + + extra_short = xread_char(src_fd) + (xread_char(src_fd) << 8); + while (extra_short > 0) { + /* Ignore extra field */ + xread_char(src_fd); + extra_short--; + } + } + + /* Discard original name if any */ + if (header.formatted.flags & 0x08) { + /* bit 3 set: original file name present */ + while(xread_char(src_fd) != 0); + } + + /* Discard file comment if any */ + if (header.formatted.flags & 0x10) { + /* bit 4 set: file comment present */ + while(xread_char(src_fd) != 0); + } + + /* Read the header checksum */ + if (header.formatted.flags & 0x02) { + xread_char(src_fd); + xread_char(src_fd); + } + + return; +} Index: rockbox/apps/plugins/mww/SOURCES =================================================================== --- rockbox/apps/plugins/mww/SOURCES (revision 0) +++ rockbox/apps/plugins/mww/SOURCES (revision 0) @@ -0,0 +1,6 @@ +mww.c +mwdb.c +mallocer.c +inflate.c +btsearch.c + Index: rockbox/apps/plugins/mww/inflate.c =================================================================== --- rockbox/apps/plugins/mww/inflate.c (revision 0) +++ rockbox/apps/plugins/mww/inflate.c (revision 0) @@ -0,0 +1,1041 @@ +// /* vi: set sw=4 ts=4: */ +/* + * gunzip implementation for wikimediaviewer + * (c) Frederik M.J.V., 2006. + * some bug fixes by Adam Gashlin + * gunzip implementation for busybox + * + * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. + * + * Originally adjusted for busybox by Sven Rudolph + * based on gzip sources + * + * Adjusted further by Erik Andersen to support + * files as well as stdin/stdout, and to generally behave itself wrt + * command line handling. + * + * General cleanup to better adhere to the style guide and make use of standard + * busybox functions by Glenn McGrath + * + * read_gz interface + associated hacking by Laurence Anderson + * + * Fixed huft_build() so decoding end-of-block code does not grab more bits + * than necessary (this is required by unzip applet), added inflate_cleanup() + * to free leaked bytebuffer memory (used in unzip.c), and some minor style + * guide cleanups by Ed Clark + * + * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1992-1993 Jean-loup Gailly + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ +#include +/*#include */ +/*#include */ +#ifndef NULL +#define NULL 0 +#endif +#define ENABLE_DESKTOP 0 +#define USE_DESKTOP(...) +#include "mallocer.h" +#include "bbfuncs.c" +#include "inflate.h" +#include "mallocer.h" + +//#include "libbb.h" +//#include "unarchive.h" + +#ifdef SIMULATOR +#define printsim printf +#else +#define printsim(...) +#endif + +typedef struct huft_s { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned short n; /* literal, length base, or distance base */ + struct huft_s *t; /* pointer to next level of table */ + } v; +} huft_t; + +/*static void *mainmembuf;*/ +static void *huftbuffer1; +static void *huftbuffer2; +//#define MAINMEM_MMP0 7 +#define HUFT_MMP1 8 +#define HUFT_MMP2 9 +static int gunzip_src_fd; +unsigned int gunzip_bytes_out; /* number of output bytes */ +static unsigned int gunzip_outbuf_count; /* bytes in output buffer */ + +/* gunzip_window size--must be a power of two, and + * at least 32K for zip's deflate method */ +enum { gunzip_wsize = 0x8000 }; +static unsigned char *gunzip_window; +static uint32_t ifl_total; + +//static uint32_t *gunzip_crc_table; +uint32_t gunzip_crc; + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + +/* bitbuffer */ +static unsigned int gunzip_bb; /* bit buffer */ +static unsigned char gunzip_bk; /* bits in bit buffer */ + +/* These control the size of the bytebuffer */ +static unsigned int bytebuffer_max = 0x8000; +static unsigned char *bytebuffer = NULL; +static unsigned int bytebuffer_offset = 0; +static unsigned int bytebuffer_size = 0; + +static const unsigned short mask_bits[] = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* Copy lengths for literal codes 257..285 */ +static const unsigned short cplens[] = { + 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, 0, 0 +}; + +/* note: see note #13 above about the 258 in this list. */ +/* Extra bits for literal codes 257..285 */ +static const unsigned char cplext[] = { + 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, 99, 99 +}; /* 99==invalid */ + +/* Copy offsets for distance codes 0..29 */ +static const unsigned short cpdist[] = { + 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 +}; + +/* Extra bits for distance codes */ +static const unsigned char cpdext[] = { + 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 +}; + +/* Tables for deflate from PKZIP's appnote.txt. */ +/* Order of the bit length code lengths */ +static const unsigned char border[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + +static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required) +{ + while (*current < required) { + if (bytebuffer_offset >= bytebuffer_size) { + /* Leave the first 4 bytes empty so we can always unwind the bitbuffer + * to the front of the bytebuffer, leave 4 bytes free at end of tail + * so we can easily top up buffer in check_trailer_gzip() */ + if (1 > (bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], bytebuffer_max - 8))) + error_die("unexpected end of file"); + bytebuffer_size += 4; + bytebuffer_offset = 4; + } + bitbuffer |= ((unsigned int) bytebuffer[bytebuffer_offset]) << *current; + bytebuffer_offset++; + *current += 8; + } + return(bitbuffer); +} + +/* + * Free the malloc'ed tables built by huft_build(), which makes a linked + * list of the tables it made, with the links in a dummy first entry of + * each table. + * t: table to free + */ +static int huft_free(huft_t * t,unsigned char bufnum) +{ + wpw_reset_mempool(bufnum); + if(t==0){} +#if 0 + huft_t *p; + huft_t *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (huft_t *) NULL) { + q = (--p)->v.t; + free((char *) p); + p = q; + } +#endif + return 0; +} + +/* Given a list of code lengths and a maximum table size, make a set of + * tables to decode that set of codes. Return zero on success, one if + * the given code set is incomplete (the tables are still built in this + * case), two if the input is invalid (all zero length codes or an + * oversubscribed set of lengths), and three if not enough memory. + * + * b: code lengths in bits (all assumed <= BMAX) + * n: number of codes (assumed <= N_MAX) + * s: number of simple-valued codes (0..s-1) + * d: list of base values for non-simple codes + * e: list of extra bits for non-simple codes + * t: result: starting table + * m: maximum lookup bits, returns actual + * bufnum: the number of the memory pool to fetch memory from + */ +static +int huft_build(unsigned int *b, const unsigned int n, + const unsigned int s, const unsigned short *d, + const unsigned char *e, huft_t ** t, unsigned int *m,unsigned char bufnum) +{ + unsigned a=0; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned eob_len=0; /* length of end-of-block code (value 256) */ + unsigned f=0; /* i repeats in table every f entries */ + int g=0; /* maximum code length */ + int htl=0; /* table level */ + unsigned i=0; /* counter, current code */ + unsigned j=0; /* counter */ + int k=0; /* number of bits in current code */ + unsigned *p; /* pointer into c[], b[], or v[] */ + huft_t *q; /* points to current table */ + huft_t r; /* table entry for structure assignment */ + huft_t *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + int ws[BMAX+1]; /* bits decoded stack */ + int w=0; /* bits decoded */ + unsigned x[BMAX + 1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y=0; /* number of dummy codes added */ + unsigned z=0; /* number of entries in current table */ + + /* Length of EOB code, if any */ + eob_len = n > 256 ? b[256] : BMAX; + + /* Generate counts for each bit length */ + memset((void *)c, 0, sizeof(c)); + p = b; + i = n; + do { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) { /* null input--all zero length codes */ + *t = (huft_t *) NULL; + *m = 0; + return 2; + } + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; (c[j] == 0) && (j <= BMAX); j++); + k = j; /* minimum code length */ + for (i = BMAX; (c[i] == 0) && i; i--); + g = i; /* maximum code length */ + *m = (*m < j) ? j : ((*m > i) ? i : *m); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) { + if ((y -= c[j]) < 0) { + return 2; /* bad input: more codes than bits */ + } + } + if ((y -= c[i]) < 0) { + return 2; + } + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; + xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; + i = 0; + do { + if ((j = *p++) != 0) { + v[x[j]++] = i; + } + } while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + htl = -1; /* no tables yet--level -1 */ + w = ws[0] = 0; /* bits decoded */ + u[0] = (huft_t *) NULL; /* just to keep compilers happy */ + q = (huft_t *) NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) { + a = c[k]; + while (a--) { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > ws[htl + 1]) { + w = ws[++htl]; + + /* compute minimum size table less than or equal to *m bits */ + z = (z = g - w) > *m ? *m : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table */ + /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) { /* try smaller tables up to z bits */ + if ((f <<= 1) <= *++xp) { + break; /* enough codes to use up j bits */ + } + f -= *xp; /* else deduct codes from patterns */ + } + } + j = ((unsigned)(w + j) > eob_len && (unsigned)w < eob_len) ? eob_len - w : j; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + ws[htl+1] = w + j; /* set bits decoded in stack */ + + /* allocate and link in new table */ + q = (huft_t *) wpw_malloc(bufnum,(z + 1) * sizeof(huft_t)); + //q = (huft_t *) malloc(/*bufnum,*/(z + 1) * sizeof(huft_t)); + if(q==0){ + //printf("Spaceprob\n"); + return 3; + } + + *t = q + 1; /* link to list for huft_free() */ + t = &(q->v.t); + u[htl] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (htl) { + x[htl] = i; /* save pattern for backing up */ + r.b = (unsigned char) (w - ws[htl - 1]); /* bits to dump before this table */ + r.e = (unsigned char) (16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> ws[htl - 1]; + u[htl - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (unsigned char) (k - w); + if (p >= v + n) { + r.e = 99; /* out of values--invalid code */ + } else if (*p < s) { + r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ + r.v.n = (unsigned short) (*p++); /* simple code is just the value */ + } else { + r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) { + q[j] = r; + } + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) { + i ^= j; + } + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[htl]) { + w = ws[--htl]; + } + } + } + + /* return actual size of base table */ + *m = ws[1]; + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + * + * tl, td: literal/length and distance decoder tables + * bl, bd: number of bits decoded by tl[] and td[] + */ +int inflate_codes_resumeCopy = 0; +static int inflate_codes(huft_t * my_tl, huft_t * my_td, const unsigned int my_bl, const unsigned int my_bd, int setup) +{ + static unsigned int e; /* table entry flag/number of extra bits */ + static unsigned int n, d; /* length and index for copy */ + static unsigned int w; /* current gunzip_window position */ + static huft_t *t; /* pointer to table entry */ + static unsigned int ml, md; /* masks for bl and bd bits */ + static unsigned int b; /* bit buffer */ + static unsigned int k; /* number of bits in bit buffer */ + static huft_t *tl, *td; + static unsigned int bl, bd; + + if (setup) { // 1st time we are called, copy in variables + tl = my_tl; + td = my_td; + bl = my_bl; + bd = my_bd; + /* make local copies of globals */ + b = gunzip_bb; /* initialize bit buffer */ + k = gunzip_bk; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + return 0; // Don't actually do anything the first time + } + + if (inflate_codes_resumeCopy) goto do_copy; + + while (1) { /* do until end of block */ + b = fill_bitbuffer(b, &k, bl); + if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) + do { + if (e == 99) { + error_die("inflate_codes error 1"); + } + b >>= t->b; + k -= t->b; + e -= 16; + b = fill_bitbuffer(b, &k, e); + } while ((e = + (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + if (e == 16) { /* then it's a literal */ + gunzip_window[w++] = (unsigned char) t->v.n; + if (w == gunzip_wsize) { + gunzip_outbuf_count = (w); + //flush_gunzip_window(); + w = 0; + return 1; // We have a block to read + } + } else { /* it's an EOB or a length */ + + /* exit if end of block */ + if (e == 15) { + break; + } + + /* get length of block to copy */ + b = fill_bitbuffer(b, &k, e); + n = t->v.n + ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; + + /* decode distance of block to copy */ + b = fill_bitbuffer(b, &k, bd); + if ((e = (t = td + ((unsigned) b & md))->e) > 16) + do { + if (e == 99) + error_die("inflate_codes error 2"); + b >>= t->b; + k -= t->b; + e -= 16; + b = fill_bitbuffer(b, &k, e); + } while ((e = + (t = + t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + b = fill_bitbuffer(b, &k, e); + d = w - t->v.n - ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; + + /* do the copy */ +do_copy: do { + n -= (e = + (e = + gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e); + /* copy to new buffer to prevent possible overwrite */ + if (w - d >= e) { /* (this test assumes unsigned comparison) */ + memcpy(gunzip_window + w, gunzip_window + d, e); + w += e; + d += e; + } else { + /* do it slow to avoid memcpy() overlap */ + /* !NOMEMCPY */ + do { + gunzip_window[w++] = gunzip_window[d++]; + } while (--e); + } + if (w == gunzip_wsize) { + gunzip_outbuf_count = (w); + if (n) inflate_codes_resumeCopy = 1; + else inflate_codes_resumeCopy = 0; + //flush_gunzip_window(); + w = 0; + return 1; + } + } while (n); + inflate_codes_resumeCopy = 0; + } + } + + /* restore the globals from the locals */ + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = b; /* restore global bit buffer */ + gunzip_bk = k; + + /* normally just after call to inflate_codes, but save code by putting it here */ + /* free the decoding tables, return */ + huft_free(tl,HUFT_MMP1); + huft_free(td,HUFT_MMP2); + + /* done */ + return 0; +} + +static int inflate_stored(int my_n, int my_b_stored, int my_k_stored, int setup) +{ + static unsigned int n, b_stored, k_stored, w; + if (setup) { + n = my_n; + b_stored = my_b_stored; + k_stored = my_k_stored; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ + return 0; // Don't do anything first time + } + + /* read and output the compressed data */ + while (n--) { + b_stored = fill_bitbuffer(b_stored, &k_stored, 8); + gunzip_window[w++] = (unsigned char) b_stored; + if (w == gunzip_wsize) { + gunzip_outbuf_count = (w); + //flush_gunzip_window(); + w = 0; + b_stored >>= 8; + k_stored -= 8; + return 1; // We have a block + } + b_stored >>= 8; + k_stored -= 8; + } + + /* restore the globals from the locals */ + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = b_stored; /* restore global bit buffer */ + gunzip_bk = k_stored; + return 0; // Finished +} + +/* + * decompress an inflated block + * e: last block flag + * + * GLOBAL VARIABLES: bb, kk, + */ + // Return values: -1 = inflate_stored, -2 = inflate_codes +static int inflate_block(int *e) +{ + unsigned t; /* block type */ + unsigned int b; /* bit buffer */ + unsigned int k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + + b = gunzip_bb; + k = gunzip_bk; + + /* read in last block bit */ + b = fill_bitbuffer(b, &k, 1); + *e = (int) b & 1; + b >>= 1; + k -= 1; + + /* read in block type */ + b = fill_bitbuffer(b, &k, 2); + t = (unsigned) b & 3; + b >>= 2; + k -= 2; + + /* restore the global bit buffer */ + gunzip_bb = b; + gunzip_bk = k; + + /* inflate that block type */ + switch (t) { + case 0: /* Inflate stored */ + { + unsigned int n=0; /* number of bytes in block */ + unsigned int b_stored=0; /* bit buffer */ + unsigned int k_stored=0; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b_stored = gunzip_bb; /* initialize bit buffer */ + k_stored = gunzip_bk; + + /* go to byte boundary */ + n = k_stored & 7; + b_stored >>= n; + k_stored -= n; + + /* get the length and its complement */ + b_stored = fill_bitbuffer(b_stored, &k_stored, 16); + n = ((unsigned) b_stored & 0xffff); + b_stored >>= 16; + k_stored -= 16; + + b_stored = fill_bitbuffer(b_stored, &k_stored, 16); + if (n != (unsigned) ((~b_stored) & 0xffff)) { + return 1; /* error in compressed data */ + } + b_stored >>= 16; + k_stored -= 16; + + inflate_stored(n, b_stored, k_stored, 1); // Setup inflate_stored + return -1; + } + case 1: /* Inflate fixed + * decompress an inflated type 1 (fixed Huffman codes) block. We should + * either replace this with a custom decoder, or at least precompute the + * Huffman tables. + */ + { + int i; /* temporary variable */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + unsigned int bl; /* lookup bits for tl */ + unsigned int bd; /* lookup bits for td */ + unsigned int l[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) { + l[i] = 8; + } + for (; i < 256; i++) { + l[i] = 9; + } + for (; i < 280; i++) { + l[i] = 7; + } + for (; i < 288; i++) { /* make a complete, but wrong code set */ + l[i] = 8; + } + bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl,HUFT_MMP1)) != 0) { + return i; + } + + /* set up distance table */ + for (i = 0; i < 30; i++) { /* make an incomplete code set */ + l[i] = 5; + } + bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd,HUFT_MMP2)) > 1) { + huft_free(tl,HUFT_MMP1); + return i; + } + + /* decompress until an end-of-block code */ + inflate_codes(tl, td, bl, bd, 1); // Setup inflate_codes + + /* huft_free code moved into inflate_codes */ + + return -2; + } + case 2: /* Inflate dynamic */ + { + const int dbits = 6; /* bits in base distance lookup table */ + const int lbits = 9; /* bits in base literal/length lookup table */ + + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + unsigned int i; /* temporary variables */ + unsigned int j; + unsigned int l; /* last length */ + unsigned int m; /* mask for bit lengths table */ + unsigned int n; /* number of lengths to get */ + unsigned int bl; /* lookup bits for tl */ + unsigned int bd; /* lookup bits for td */ + unsigned int nb; /* number of bit length codes */ + unsigned int nl; /* number of literal/length codes */ + unsigned int nd; /* number of distance codes */ + + unsigned int ll[286 + 30]; /* literal/length and distance code lengths */ + unsigned int b_dynamic; /* bit buffer */ + unsigned int k_dynamic; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b_dynamic = gunzip_bb; + k_dynamic = gunzip_bk; + + /* read in table lengths */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); + nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of literal/length codes */ + + b_dynamic >>= 5; + k_dynamic -= 5; + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); + nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance codes */ + + b_dynamic >>= 5; + k_dynamic -= 5; + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4); + nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length codes */ + + b_dynamic >>= 4; + k_dynamic -= 4; + if (nl > 286 || nd > 30) { + return 1; /* bad lengths */ + } + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) { + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); + ll[border[j]] = (unsigned int) b_dynamic & 7; + b_dynamic >>= 3; + k_dynamic -= 3; + } + for (; j < 19; j++) { + ll[border[j]] = 0; + } + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl,HUFT_MMP1); + if (i != 0) { + if (i == 1) { + huft_free(tl,HUFT_MMP1); + } + return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned int) i < n) { + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl); + j = (td = tl + ((unsigned int) b_dynamic & m))->b; + b_dynamic >>= j; + k_dynamic -= j; + j = td->v.n; + if (j < 16) { /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + } else if (j == 16) { /* repeat last length 3 to 6 times */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2); + j = 3 + ((unsigned int) b_dynamic & 3); + b_dynamic >>= 2; + k_dynamic -= 2; + if ((unsigned int) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = l; + } + } else if (j == 17) { /* 3 to 10 zero length codes */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); + j = 3 + ((unsigned int) b_dynamic & 7); + b_dynamic >>= 3; + k_dynamic -= 3; + if ((unsigned int) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } else { /* j == 18: 11 to 138 zero length codes */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7); + j = 11 + ((unsigned int) b_dynamic & 0x7f); + b_dynamic >>= 7; + k_dynamic -= 7; + if ((unsigned int) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } + } + + /* free decoding table for trees */ + huft_free(tl,HUFT_MMP1); + + /* restore the global bit buffer */ + gunzip_bb = b_dynamic; + gunzip_bk = k_dynamic; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl,HUFT_MMP1)) != 0) { + if (i == 1) { + error_die("Incomplete literal tree"); + huft_free(tl,HUFT_MMP1); + } + printsim("incomplete code set\n"); + return i; /* incomplete code set */ + } + + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd,HUFT_MMP2)) != 0) { + if (i == 1) { + error_die("incomplete distance tree"); + huft_free(td,HUFT_MMP2); + } + huft_free(tl,HUFT_MMP1); + printsim("incomplete code set2\n"); + return i; /* incomplete code set */ + } + + /* decompress until an end-of-block code */ + inflate_codes(tl, td, bl, bd, 1); // Setup inflate_codes + + /* huft_free code moved into inflate_codes */ + + return -2; + } + default: + /* bad block type */ + //error_die("bad block type %d", t); + error_die("bad block type"); + } + printsim("default error\n"); + return 0; +} + +static void calculate_gunzip_crc(void) +{ + unsigned int n; + for (n = 0; n < gunzip_outbuf_count; n++) { + gunzip_crc = crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); + } + gunzip_bytes_out += gunzip_outbuf_count; +} + +int inflate_get_next_window_method = -1; // Method == -1 for stored, -2 for codes +int inflate_get_next_window_e = 0; +int inflate_get_next_window_needAnotherBlock = 1; + +static int inflate_get_next_window(void) +{ + gunzip_outbuf_count = 0; + + while(1) { + int ret=0; + if (inflate_get_next_window_needAnotherBlock) { + if(inflate_get_next_window_e) { + printsim("last block\n"); + calculate_gunzip_crc(); + inflate_get_next_window_e = 0; + inflate_get_next_window_needAnotherBlock = 1; + return 0; + } // Last block + inflate_get_next_window_method = inflate_block(&inflate_get_next_window_e); + inflate_get_next_window_needAnotherBlock = 0; + } + switch (inflate_get_next_window_method) { + case -1: ret = inflate_stored(0,0,0,0); + break; + case -2: ret = inflate_codes(0,0,0,0,0); + break; + //default: printf("inflate error %d\n", method); + // exit(0); + default: {error_die("inflate error"); printsim("inflate error method=%d\n",inflate_get_next_window_method);} + } + if (ret == 1) { + calculate_gunzip_crc(); + printsim("more data left\n"); + return 1; // More data left + } else inflate_get_next_window_needAnotherBlock = 1; // End of that block + } + /* Doesnt get here */ +} + +/* Initialise bytebuffer, be careful not to overfill the buffer */ +void inflate_init(unsigned int bufsize) +{ + /* Set the bytebuffer size, default is same as gunzip_wsize */ + bytebuffer_max = bufsize + 8; + bytebuffer_offset = 4; + bytebuffer_size = 0; +} + +void inflate_cleanup(void) +{ + //free(bytebuffer); +} + + +USE_DESKTOP(long long) int +inflate_unzip(int in,char* outbuffer,uint32_t outbuflen) +{ + USE_DESKTOP(long long total = 0;) + //ssize_t nwrote=0; + typedef void (*sig_type) (int); + + /* Allocate all global buffers (for DYN_ALLOC option) */ + //gunzip_window = malloc(gunzip_wsize); + gunzip_outbuf_count = 0; + gunzip_bytes_out = 0; + gunzip_src_fd = in; + + /* initialize gunzip_window, bit buffer */ + gunzip_bk = 0; + gunzip_bb = 0; + + /* Create the crc table */ + //gunzip_crc_table = crc_table;//crc32_filltable(0); + gunzip_crc = ~0; + + /* Allocate space for buffer */ + //bytebuffer = malloc(bytebuffer_max); + while(1) { + int ret = inflate_get_next_window(); + if((signed int)outbuflen-(signed int)gunzip_outbuf_count<0){ + error_msg("write_error"); + return -1; + } + memcpy(outbuffer,gunzip_window,gunzip_outbuf_count); + outbuffer+=sizeof(char)*gunzip_outbuf_count; + ifl_total+=sizeof(char)*gunzip_outbuf_count; + outbuflen-=gunzip_outbuf_count; + USE_DESKTOP(total += gunzip_outbuf_count;) + if (ret == 0) break; + } + + /* Cleanup */ + //free(gunzip_window); + //free(gunzip_crc_table); + + /* Store unused bytes in a global buffer so calling applets can access it */ + if (gunzip_bk >= 8) { + /* Undo too much lookahead. The next read will be byte aligned + * so we can discard unused bits in the last meaningful byte. */ + bytebuffer_offset--; + bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff; + gunzip_bb >>= 8; + gunzip_bk -= 8; + } + return USE_DESKTOP(total) + 0; +} + + +USE_DESKTOP(long long) int +inflate_gunzip(int in, char* outbuffer,uint32_t outbuflen) +{ + uint32_t stored_crc = 0; + unsigned int count; + USE_DESKTOP(long long total = )inflate_unzip(in, outbuffer,outbuflen); + + USE_DESKTOP(if (total < 0) return total;) + + /* top up the input buffer with the rest of the trailer */ + count = bytebuffer_size - bytebuffer_offset; + if (count < 8) { + xread(in, &bytebuffer[bytebuffer_size], 8 - count); + bytebuffer_size += 8 - count; + } + for (count = 0; count != 4; count++) { + stored_crc |= (bytebuffer[bytebuffer_offset] << (count * 8)); + bytebuffer_offset++; + } + + /* Validate decompression - crc */ + if (stored_crc != (~gunzip_crc)) { + error_msg("crc error"); + printsim("crc error\n"); + return -1; + } + + /* Validate decompression - size */ + if ((signed int)gunzip_bytes_out != + (bytebuffer[bytebuffer_offset] | (bytebuffer[bytebuffer_offset+1] << 8) | + (bytebuffer[bytebuffer_offset+2] << 16) | (bytebuffer[bytebuffer_offset+3] << 24))) { + error_msg("incorrect length"); + printsim("incorrect length"); + return -1; + } + + return USE_DESKTOP(total) + 0; +} + +/*An allocated memory buffer at least 0x13100 (72448) bytes long*/ +uint32_t decompress(const char *inflenme,char* outbuffer,uint32_t outbuflen,uint32_t offset,char* membuf){ + signed char status=0; + int exitcode=0; + int src_fd; + ifl_total=0; + /* reset statics */ + inflate_codes_resumeCopy = 0; + inflate_get_next_window_method = -1; // Method == -1 for stored, -2 for codes + inflate_get_next_window_e = 0; + inflate_get_next_window_needAnotherBlock = 1; + /* init */ + inflate_init(0x8000-8); + /*Memory init*/ +/* wpw_init_mempool_pdm(rb,MAINMEM_MMP0,(unsigned char*)membuf,0x13100);*/ + huftbuffer1=membuf;//wpw_malloc(MAINMEM_MMP0,0x2A00); + huftbuffer2=membuf+0x2A00;//wpw_malloc(MAINMEM_MMP0,0x700); + gunzip_window=membuf+0x2A00+0xA00;//wpw_malloc(MAINMEM_MMP0,0x8000); + bytebuffer=membuf+0x2A00+0xA00+0x8000;//wpw_malloc(MAINMEM_MMP0,0x8000); + wpw_init_mempool_pdm(rb,HUFT_MMP1,(unsigned char*)huftbuffer1,0x2A00); + wpw_init_mempool_pdm(rb,HUFT_MMP2,(unsigned char*)huftbuffer2,0xA00); + + src_fd = rb->open(inflenme, O_RDONLY); + if(src_fd==-1) + return 0; + //dst_fd = open(outfn, O_WRONLY|O_CREAT, 0666); + rb->lseek(src_fd,offset,SEEK_SET); + if ((exitcode=xread_char(src_fd)) == 0x1f) { + unsigned char magic2; + magic2 = xread_char(src_fd); + if (magic2 == 0x8b) { + check_header_gzip(src_fd); // FIXME: xfunc? _or_die? + status = inflate_gunzip(src_fd, outbuffer,outbuflen); + } else { + error_msg("invalid magic"); + printsim("invalid magic\n"); + exitcode = -1; + } + if (status < 0) { + error_msg("error inflating"); + printsim("error inflating\n"); + exitcode = -1; + } + } else { + error_msg("invalid magic"); + printsim("invalid magic\n"); + exitcode = -1; + } + wpw_destroy_mempool(HUFT_MMP1); + wpw_destroy_mempool(HUFT_MMP2); + rb->close(src_fd); + //wpw_destroy_mempool(MAINMEM_MMP0); +/* free(huftbuffer1); + free(huftbuffer2); + free(gunzip_window); + free(bytebuffer);*/ + //free(mainmembuf); + if(exitcode==-1)return 0; + return ifl_total; +} +// int main(int argc,const char** argv){ +// //void *membuf=malloc(0x11B00); +// void *membuf=malloc(0x13100); +// decompress(argv[1],argv[2],atol(argv[3]),(const char*) membuf); +// free(membuf); +// } Index: rockbox/apps/plugins/mww/mallocer.h =================================================================== --- rockbox/apps/plugins/mww/mallocer.h (revision 0) +++ rockbox/apps/plugins/mww/mallocer.h (revision 0) @@ -0,0 +1,21 @@ +#define MEMPOOL_MAX 10 +#define INROCKBOX +//#define DBWPWM +#ifdef INROCKBOX +#include +#include "plugin.h" +int wpw_init_mempool(struct plugin_api* rb,unsigned char mempool); +int wpw_init_mempool_pdm(struct plugin_api* rb,unsigned char mempool, unsigned char* mem,long memsize); +#else +#include +#include +#include +void wpw_init_mempool(unsigned char mempool,unsigned char* mem,long memsize); +#endif +void wpw_reset_mempool(unsigned char mempool); +void wpw_destroy_mempool(unsigned char mempool); +void* wpw_malloc(unsigned char mempool,size_t size); +void* wpw_calloc(unsigned char mempool,size_t nmemb, size_t size); +void codec_free(unsigned char mempool,void* ptr); +void* wpw_realloc(unsigned char mempool,void* ptr, size_t size); +long wpw_available(unsigned char mempool); Index: rockbox/apps/plugins/mww/testmain.c =================================================================== --- rockbox/apps/plugins/mww/testmain.c (revision 0) +++ rockbox/apps/plugins/mww/testmain.c (revision 0) @@ -0,0 +1,76 @@ +#ifndef NO_GZIP +# define GUNZIP +#endif +#include +#include +#include +#include "zlib.h" +#define CHUNK 16384 +/* Decompress from file source to file dest until stream ends or EOF. + inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_DATA_ERROR if the deflate data is + invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and + the version of the library linked do not match, or Z_ERRNO if there + is an error reading or writing the files. */ +int inf(FILE *source, FILE *dest) +{ + int ret; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + /* decompress until deflate stream ends or end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = in; + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} +/* compress or decompress from stdin to stdout */ +int main(int argc, char **argv) +{ + int ret; + /* do decompression if -d specified */ + ret = inf(stdin, stdout); + if (ret != Z_OK) + printf("Error:%d\n",ret); + return ret; +} Index: rockbox/apps/plugins/mww/inflate.h =================================================================== --- rockbox/apps/plugins/mww/inflate.h (revision 0) +++ rockbox/apps/plugins/mww/inflate.h (revision 0) @@ -0,0 +1,9 @@ +#ifndef INFLATE_H +#define INFLATE_H +#include +#include "plugin.h" +extern struct plugin_api *rb; +#define memset rb->memset +#define memcpy rb->memcpy +uint32_t decompress(const char *inflenme,char* outbuffer,uint32_t outbuflen,uint32_t offset,char* membuf); +#endif Index: rockbox/apps/plugins/mww/mwdb.c =================================================================== --- rockbox/apps/plugins/mww/mwdb.c (revision 0) +++ rockbox/apps/plugins/mww/mwdb.c (revision 0) @@ -0,0 +1,98 @@ +#include "mallocer.h" /*mallocer resetable memory allocator*/ +#include "inflate.h" +#include "btsearch.h" +#include +#ifdef SIMULATOR +#define printsim printf +#else +#define printsim(...) +#endif +/*Remember to require this:*/ +extern struct plugin_api *rb; + +unsigned int mwdb_p_xtpt; + +int mwdb_nprintf(const char *fmt, ...) +{ + char p_buf[50]; + bool ok; + va_list ap; + + va_start(ap, fmt); + ok = rb->vsnprintf(p_buf,sizeof(p_buf), fmt, ap); + va_end(ap); + + rb->lcd_putsxy(1,mwdb_p_xtpt, (unsigned char *)p_buf); + rb->lcd_update(); + + mwdb_p_xtpt+=rb->font_get(FONT_UI)->height; + if(mwdb_p_xtpt>LCD_HEIGHT-rb->font_get(FONT_UI)->height) + { + mwdb_p_xtpt=0; + rb->lcd_clear_display(); + } + return 1; +} + +int mwdb_findarticle(const char* filename, + char* artnme, + uint16_t artnmelen, + uint32_t * res_lo, + uint32_t * res_hi, + bool progress, + bool promptname, + bool casesense){ + int fd; + char fnbuf[rb->strlen(filename)+6]; + if(promptname) { +#if 1 + if (rb->kbd_input(artnme,artnmelen)) { + artnme[0]='\0'; + return false; // proper abort on keyboard abort + } +#else + rb->kbd_input(artnme,artnmelen); // handy for ipod keyboard (accept is harder to enter than abort) +#endif + } + rb->snprintf(fnbuf,rb->strlen(filename)+6,"%s.wwi",filename); + fd = rb->open(fnbuf, 0); + if (fd==-1) + return false; + if(progress){ + mwdb_p_xtpt=0; + rb->lcd_clear_display(); + mwdb_nprintf("Searching..."); + } + search_btree(fd,artnme,rb->strlen(artnme),0,res_lo,res_hi,casesense); + rb->close(fd); + if(*res_hi==0){//not found + //if(progress)mwdb_nprintf("Article not found"); + return false; + }else if(progress) mwdb_nprintf("Found:%d%d",*res_lo,*res_hi); + printsim("Found: %s %d %d\n",artnme,*res_lo,*res_hi); + + + return true; +} + + +int mwdb_loadarticle(const char * filename, + void * scratchmem, + void * articlemem, + uint32_t articlememlen, + uint32_t *articlelen, + uint32_t res_lo, + uint32_t res_hi) { + char fnbuf[rb->strlen(filename)+6]; + + mwdb_p_xtpt=0; + rb->lcd_clear_display(); + mwdb_nprintf("Loading %d%d...",res_lo,res_hi); + + rb->snprintf(fnbuf,rb->strlen(filename)+6,"%s%lu.wwa",filename,res_lo); + *articlelen=decompress(fnbuf,articlemem,articlememlen,res_hi,scratchmem); + ((unsigned char*)articlemem)[*articlelen]='\0'; + + return true; +} + Index: apps/plugins/mww/mww.c =================================================================== --- rockbox/apps/plugins/mww/mww.c (revision 0) +++ rockbox/apps/plugins/mww/mww.c (revision 0) @@ -0,0 +1,1437 @@ +/*************************************************************************** + * + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * + * Copyright (C) 2006 Frederik M.J. Vestre + * Copyright (C) 2006 Adam Gashlin + * + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "plugin.h" +#include +#include "../lib/playback_control.h" +#include +#include "mallocer.h" /*mallocer resetable memory allocator*/ +#include "mwdb.h" +#include "lib/oldmenuapi.h" +#include "lib/oldmenuapi.h" +#if LCD_DEPTH > 1 +//#define COLORLINKS +#endif + +PLUGIN_HEADER + +struct plugin_api *rb; + +/* change on any change to file format, histstate */ +#define SAVE_FILE_VERSION_MAGIC 0x12340004 + +static bool wrquit=false; +static char *filename; /* name of database, without extension */ + +#define MAINMEMBUF 0 +//#define INFLATEBUF 1 +//#define ARTICLEBUF 2 +/*static void *mainmembuf;*/ + +void *inflatebuf; /* heap for gunzip */ +char *articlebuf; /* destination for uncompressed article */ +uint32_t articlebuflen=0; /* size of the article buffer */ +uint32_t articlelen=0; /* used size of the article buffer */ + +int lastlinkcount=0; /* set by render() to the number of links found */ + +/* provides everything render() needs to know to render a screen */ +struct linestate { + int32_t renderoff; + int renderlen; + int32_t linknameoff; + int inlink,inlinkname; +#ifdef COLORLINKS + uint8_t inem; +#endif + int eof; /* should be interpreted as disallowing further scrolling down */ +}; + +#define ARTICLENAMEBUF_LENGTH 255 + +/* where we'll be scrolling next */ +struct linestate curlinestate,nextlinestate; + +/* scrollback, to allow scrolling backwards fairly quickly (without some memory entire article + might need to be reparsed to find context of previous line) */ +/* stack, up to SCROLLBACK_LENGTH, past that the oldest entry is discarded */ +#define SCROLLBACK_LENGTH 50 +int curlinehist,linehistdepth; +int curline; +struct linestate linehist[SCROLLBACK_LENGTH]; + +/* bookmarks, for going back to a previous article */ + +struct bookstate { + char name[ARTICLENAMEBUF_LENGTH]; + int32_t curoff; + uint32_t res_lo; /* avoid searching again */ + uint32_t res_hi; +}; + +/* history, for going back to a previous article */ + +struct histstate { + char name[ARTICLENAMEBUF_LENGTH]; + int32_t curoff; + uint32_t res_lo; /* avoid searching again */ + uint32_t res_hi; +}; + +/* + It should be possible to reconstruct a linestate from a histstate as follows: + 1) load the article given by res_lo, res_hi + 2) linestate=0 + 3) while linestate.renderoffclose(fd);*/ +} + +static void set_article_offset(int32_t off); +static void reset_scrollback(void); +static void advance_scrollback(int a, int dorender); +static void reset_history(void); +static void advance_history(int d); + +int load_bookmarks(const char * filename) { + char fnbuf[MAX_PATH+1]; + int fd; + int i,booki; + uint32_t magic=0; + + rb->snprintf(fnbuf,MAX_PATH,"%s.wwb",filename); + fd = rb->open(fnbuf, O_RDONLY); + if (fd<0) return 0; + + if (rb->read(fd,&magic,sizeof(magic))<=0) {rb->close(fd); return 0;} + if (magic!=SAVE_FILE_VERSION_MAGIC) {rb->close(fd); return 0;} + + if (rb->read(fd,&booki,sizeof(booki))<=0) {rb->close(fd); return 0;} + if (booki<=0) {rb->close(fd); return 0;} + + for (i=0;iread(fd,book+i,sizeof(struct bookstate))<=0) {rb->close(fd); return 0;} + } + bookdepth=booki; + + rb->close(fd); + + return 1; +} + +void save_bookmark(const char * filename) { + char fnbuf[MAX_PATH+1]; + int fd; + int i,booki; + uint32_t magic; + + rb->snprintf(fnbuf,MAX_PATH,"%s.wwb",filename); + + fd = rb->open(fnbuf, O_WRONLY|O_CREAT); + if (fd<0) return; + + magic=SAVE_FILE_VERSION_MAGIC; + booki=0; + + rb->write(fd, &magic, sizeof(magic)); + rb->write(fd, &bookdepth, sizeof(bookdepth)); + + for (i=0;iwrite(fd, book+booki, sizeof(struct bookstate)); + booki=(booki+1); + } + + rb->close(fd); +} + + +void add_bookmark(void) { + rb->strcpy(book[bookdepth].name,hist[curhist].name); + book[bookdepth].curoff=hist[curhist].curoff; + book[bookdepth].res_lo=hist[curhist].res_lo; + book[bookdepth].res_hi=hist[curhist].res_hi; + bookdepth++; +} + +void render_bookmarks(int off) { + int i=(bookdepth-1),j,d; + int x,y,fontheight,t; + char buf[10]; + + rb->lcd_clear_display(); + + y=1; + fontheight = rb->font_get(FONT_UI)->height; + + for (j=1,d=(bookdepth);d>0 && y+fontheight=(off+1)) { + rb->snprintf(buf,10,"%3d. ",j); + rb->lcd_putsxy(1,y,buf); + rb->lcd_getstringsize(buf,&x,&t); + rb->lcd_putsxy(1+x,y,book[i].name); + y+=fontheight; + } + i--; + } + + rb->lcd_update(); +} + +void remove_bookmark(int bookviewoff) { + int i,booki; + + booki=bookdepth-bookviewoff-1; + for (i=booki;istrcpy(book[i].name,book[(i+1)].name); + book[i].curoff=book[(i+1)].curoff; + book[i].res_lo=book[(i+1)].res_lo; + book[i].res_hi=book[(i+1)].res_hi; + } + bookdepth--; +} + +void save_status(const char * filename) { + char fnbuf[MAX_PATH+1]; + int fd; + int i,histi; + uint32_t magic; + + rb->snprintf(fnbuf,MAX_PATH,"%s.wws",filename); + + fd = rb->open(fnbuf, O_WRONLY|O_CREAT); + if (fd<0) return; + + magic=SAVE_FILE_VERSION_MAGIC; + + rb->write(fd, &magic, sizeof(magic)); + rb->write(fd, &histdepth, sizeof(histdepth)); + + histi=curhist-(histdepth-1); + if (histi<0) histi+=HISTORY_LENGTH; + + for (i=0;iwrite(fd, hist+histi, sizeof(struct histstate)); + histi=(histi+1)%HISTORY_LENGTH; + + } + rb->close(fd); +} + +int load_status(const char * filename) { + char fnbuf[MAX_PATH+1]; + int fd; + int i,histi; + uint32_t magic=0; + + rb->snprintf(fnbuf,MAX_PATH,"%s.wws",filename); + fd = rb->open(fnbuf, O_RDONLY); + if (fd<0) return 0; + + if (rb->read(fd,&magic,sizeof(magic))<=0) {rb->close(fd); return 0;} + if (magic!=SAVE_FILE_VERSION_MAGIC) {rb->close(fd); return 0;} + + if (rb->read(fd,&histi,sizeof(histi))<=0) {rb->close(fd); return 0;} + if (histi<=0) {rb->close(fd); return 0;} + + //reset_history(); + + for (i=0;iread(fd,hist+i,sizeof(struct histstate))<=0) {rb->close(fd); return 0;} + } + histdepth=histi; + curhist=i-1; + + rb->close(fd); + + return 1; +} + +static void set_article_offset(int32_t off) { + /* go to offset off in current article */ + printsim("set_article_offset(%d)\n",off); + reset_scrollback(); + curline=0; + //hist[curhist].curoff=0; + rb->memset(&curlinestate,0,sizeof(curlinestate)); + rb->memset(&nextlinestate,0,sizeof(nextlinestate)); + + hist[curhist].curoff=curlinestate.renderoff=10+articlebuf[8]; + curlinestate.renderlen=articlelen-10-articlebuf[8]; + + nextlinestate=render(curlinestate,1,0); + // render is done here to ensure that we correctly check eof + //nextlinestate=render(curlinestate,0,0); + //rb->lcd_clear_display(); + + while (!nextlinestate.eof && hist[curhist].curoff1) { + for (i=0;i0) { + /* if we have records to fall back on */ + linehistdepth--; + curlinehist--; + printsim("use linehist[%d]\n",curlinehist); + if (curlinehist<0) curlinehist=SCROLLBACK_LENGTH-1; + curlinestate=linehist[curlinehist]; + nextlinestate=render(curlinestate,!dorender,0); + hist[curhist].curoff=curlinestate.renderoff; + } else { + int amounttoscroll=curline; + /* redo from start */ + + reset_scrollback(); /* clear scrollback */ + set_article_offset(0); /* go to top */ + advance_scrollback(amounttoscroll,dorender); /* scoll down */ + } + + } else { + /* scroll forwards one line */ + if (!nextlinestate.eof) { + printsim("save to linehist[%d]\n",curlinehist); + linehist[curlinehist]=curlinestate; + curlinehist=(curlinehist+1)%SCROLLBACK_LENGTH; + linehistdepth++; + if (linehistdepth>SCROLLBACK_LENGTH) linehistdepth=SCROLLBACK_LENGTH; + + curlinestate=nextlinestate; + curline++; + nextlinestate=render(curlinestate,!dorender,0); + hist[curhist].curoff=curlinestate.renderoff; + } + } +} + +static void reset_history(void) { + curhist=0; + histdepth=1; +} + + +static void advance_history(int d) { + if (d==1) { + curhist=(curhist+1)%HISTORY_LENGTH; + histdepth++; + if (histdepth>HISTORY_LENGTH) histdepth=HISTORY_LENGTH; + } else if (d==-1) { + if (histdepth>1) { + curhist--; + if (curhist<0) curhist=HISTORY_LENGTH-1; + histdepth--; + } + } +} + +/* +uint16_t decode_utf8_char(const char *src,uint16_t *olen) +{ + uint16_t ucs; + const char *retchar=rb->utf8decode(src,&ucs); + *olen=retchar-src; + return ucs; +} +*/ +int iswhitespace(uint16_t c) { + return (c==' ' || c=='\n'); +} +int islinebreak(uint16_t c) { + return (c=='\n'); +} + +#define LINEBUFLEN 255 +#define MARKUP_STARTULINE 1 +#define MARKUP_ENDULINE 2 +#define MARKUP_STARTBOLD 3 +#define MARKUP_ENDBOLD 4 +#define MARKUP_STARTITALIC 5 +#define MARKUP_ENDITALIC 6 +#define MARKUP_STARTLINK 7 +#define MARKUP_ENDLINK 8 +#define MARKUP_LINEFEED 10 +#define MARKUP_MODE 15 +//#define MARKUP_MODE 15 + + int record_flag=0; /*set to 1 when recording a line to an external file*/ + +/* return next place to scroll to */ +static struct linestate render(struct linestate cur, int norender,int linktonote) { + int i; /* offset in buf */ + int x,y; /* current render location */ + const char * nextchar; /* character after the current UTF-8 character */ + int charsize; /* size of the current UTF-8 character */ + uint16_t ucs; /* current UTF-8 character */ + char buf[LINEBUFLEN+1]; /* the current line of text to be rendered */ + uint8_t underline[LCD_WIDTH]; /* should there be an underline at this pixel? */ + + int fontheight; + int first = 0; /*record only first line through*/ + char fnbuf1[MAX_PATH+1];/*for recording line of text*/ + int fd1; /*for recording line of text*/ + +#ifdef COLORLINKS + uint8_t em[LCD_WIDTH]; /* type of emphasis for this pixel */ + unsigned lastcol=0; + bool colorem=true; + rb->memset(em,0,sizeof(em)); +#endif + struct linestate nextline; /* state to return */ + + /* state to back up to when doing line break */ + int lastspace_i=0; + int lastspace_linkcount=0; + struct linestate lastspace; + + int linkcount; + int linedone=0; + int lastwaswhitespace; /* if the last character was whitespace we'll ignore subsequent whitespace */ + + printsim("render(*,%d,%d) off=%d\n",norender,linktonote,cur.renderoff); + + fontheight = rb->font_get(FONT_UI)->height; + y=1; + + linkcount=1; + lastlinkcount=0; + + nextline.renderoff=-1; + /* it's not going to be any less the end... */ + nextline.eof=cur.eof; + + if (!norender) rb->memset(underline,0,sizeof(underline)); + + while (((y+fontheight) < LCD_HEIGHT) && cur.renderlen>0) { + lastspace.renderoff=-1; + ucs=0; + lastwaswhitespace=1; /* prevent whitespace from appearing at the beginning of a line */ + /* scroll halfway down the screen */ + //if (y==(LCD_HEIGHT/fontheight/2)*fontheight+1) halfway=article; + /* see how much we can fit on a line */ + for (x=1,i=0,linedone=0;!linedone && i0;) { + /*handle markup*/ + switch (articlebuf[cur.renderoff]) { + case MARKUP_STARTULINE: + case MARKUP_STARTBOLD: + case MARKUP_STARTITALIC: +#ifdef COLORLINKS + switch (articlebuf[cur.renderoff]) { + case MARKUP_STARTULINE: + cur.inem=1; + break; + case MARKUP_STARTBOLD: + cur.inem=2; + break; + case MARKUP_STARTITALIC: + cur.inem=3; + break; + } +#endif + cur.renderlen--; + cur.renderoff++; + break; + case MARKUP_ENDULINE: + case MARKUP_ENDBOLD: + case MARKUP_ENDITALIC: +#ifdef COLORLINKS + if (cur.inem) { + cur.inem=0; + } +#endif + cur.renderlen--; + cur.renderoff++; + break; + case MARKUP_STARTLINK: + //printf("startlink\n"); + cur.inlink=1; + cur.linknameoff=cur.renderoff; + cur.renderlen--; + cur.renderoff++; + break; + case MARKUP_ENDLINK: + //printf("endlink\n"); + if (cur.inlinkname) { + cur.inlinkname=0; + linkcount++; + } + if (cur.inlink) { + /* start outputting link text */ + cur.renderlen+=cur.renderoff-cur.linknameoff; + cur.renderoff-=cur.renderoff-cur.linknameoff; + cur.linknameoff=0; + cur.inlink=0; + cur.inlinkname=1; + } + cur.renderlen--; + cur.renderoff++; + break; + case MARKUP_MODE: + if (cur.inlink) cur.linknameoff=cur.renderoff; + cur.renderlen--; + cur.renderoff++; + break; + default: + nextchar = rb->utf8decode(articlebuf+cur.renderoff,&ucs); + charsize = nextchar-cur.renderoff-articlebuf; + /* multiple newlines work */ + if (islinebreak(ucs)) {linedone=1;/* break;*/} + /* but multiple other whitespace will be ignored */ + if (!linedone && !cur.inlink && !(iswhitespace(ucs) && lastwaswhitespace)) { + /* display */ + int charwidth=rb->font_get_width(rb->font_get(FONT_UI),ucs); + + if (iswhitespace(ucs)) { + lastspace=cur; + lastspace_i=i; + lastspace_linkcount=linkcount; + lastwaswhitespace=1; + } else lastwaswhitespace=0; + + if ((x+=charwidth) > LCD_WIDTH) {linedone=1; break;} + + if (!norender) { + rb->memcpy(buf+i,articlebuf+cur.renderoff,charsize); + if (cur.inlinkname) rb->memset(underline+(x-charwidth),linkcount,charwidth); +#ifdef COLORLINKS + if (cur.inem) rb->memset(em+(x-charwidth),cur.inem,charwidth); +#endif + } + i+=charsize; + + } else { + /* hidden */ + + } + cur.renderlen-=charsize; + cur.renderoff+=charsize; + } /* end markup switch */ + } /* end for characters in a line */ + if (x>=LCD_WIDTH) { + /* the next character would be offscreen, terminate at previous space */ + if (lastspace.renderoff==-1) { + /* if we have a long word, break it here */ + } else { + cur=lastspace; + linkcount=lastspace_linkcount; + i=lastspace_i; + } + + } + + if (!norender) { + int uc,ucm,t; + //printsim("doing render\n"); + buf[(i<=LINEBUFLEN)?i:LINEBUFLEN]='\0'; + rb->lcd_putsxy(1,y, (unsigned char *)buf); + + if ((first<1) && (record_flag==1)) + { + first++; + record_flag=0; + + rb->snprintf(fnbuf1,MAX_PATH,"/wiki/%s.txt",hist[curhist].name); + + fd1 = rb->open(fnbuf1, O_WRONLY|O_APPEND|O_CREAT); + if (fd1<0) + { + rb->splash(HZ*2, "Recording NOT done"); + } + else + { + rb->write(fd1,(unsigned char *)buf,lastspace_i); + rb->write(fd1," ",1); + rb->close(fd1); + } + } + + rb->lcd_getstringsize(buf,&ucm,&t); + + int oldmode=rb->lcd_get_drawmode(); + + /* mark links */ + for (uc=0;uclcd_get_foreground(); + rb->lcd_set_drawmode(DRMODE_SOLID); + switch (em[uc]) { + case 1: + rb->lcd_set_foreground(LCD_RGBPACK(255,0,0)); + break; + case 2: + rb->lcd_set_foreground(LCD_RGBPACK(0,255,0)); + break; + case 3: + rb->lcd_set_foreground(LCD_RGBPACK(0,0,255)); + break; + } + rb->lcd_drawpixel(uc,y+fontheight-1); + rb->lcd_set_foreground(lastcol); + + } + em[uc]=0; +#endif + if (underline[uc] && uc > 1 && uc < (ucm+1)) { + if (underline[uc]==linktonote) { + rb->lcd_set_drawmode(DRMODE_COMPLEMENT); + rb->lcd_vline(uc,y,y+fontheight-1); + } else { + rb->lcd_set_drawmode(DRMODE_SOLID); + rb->lcd_drawpixel(uc,y+fontheight-1); + } + lastlinkcount=underline[uc]; + } + underline[uc]=0; + /* clear rest of line */ + if (uc >= ucm+1) { + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + rb->lcd_vline(uc,y,y+fontheight-1); + } + } + + rb->lcd_set_drawmode(oldmode); + } + + y+=fontheight; + /*scroll one line*/ + if (nextline.renderoff==-1) { + nextline=cur; + if (norender) return nextline; + } + } + if (cur.renderlen<=0) {cur.eof=1; nextline.eof=1; printsim("eof\n");} + + if (!norender) rb->lcd_update(); + return ((nextline.renderoff==-1)?cur:nextline); +} + +static void readlink(struct linestate cur, int link, char * namebuf, int buflen) { + int linkcount=0; + + rb->memset(namebuf,0,buflen); + + if (!link) return; + + /* + screen starts partway through a link + */ + if (cur.inlink || cur.inlinkname) { + printsim("starting readlink() within a link\n"); + /* seek back to the start of the link */ + while (articlebuf[cur.renderoff] != MARKUP_STARTLINK) { + cur.renderoff--; + cur.renderlen++; + } + } + + while (cur.renderlen) { + if (articlebuf[cur.renderoff] == MARKUP_STARTLINK) { + linkcount++; + if (linkcount==link) { + cur.renderoff++; + cur.renderlen--; + break; + } + } + cur.renderoff++; + cur.renderlen--; + } + if (linkcount==link) { + int i; + for (i=0;i0;) { + int charsize; + if (articlebuf[cur.renderoff]==MARKUP_ENDLINK || articlebuf[cur.renderoff]==MARKUP_MODE) break; + + charsize = rb->utf8seek(articlebuf+cur.renderoff,1); + rb->memcpy(namebuf+i,articlebuf+cur.renderoff,charsize); + cur.renderlen-=charsize; + i+=charsize; + cur.renderoff+=charsize; + } + } +} + +/* locate headings, indicated by a line beginning with = */ +/* this is unfortunately quite stupid about markup in headings */ + +static int render_outline(int inoff, int norender) { + int renderoff; + int renderlen; + int nextlineoff; + int linecount; + int intdepth=0,extdepth=0,linestart; + int charsize; + int fontheight; + int y; + + char preserv; + enum { + STATE_START, /* start of line */ + STATE_DD, /* determining depth */ + STATE_DD2, /* check closing =s */ + STATE_HTEXT, /* heading text */ + STATE_OTHERTEXT /* other text */ + } state; + + if (inoff<10) inoff=10; + renderoff=inoff; + renderlen=articlelen-renderoff; + linecount=0; + + y=1; + fontheight = rb->font_get(FONT_UI)->height; + + if (!norender) rb->lcd_clear_display(); + + if (renderoff==10) { /* we will include the article title */ + if (!norender) { + //rb->lcd_clear_display(); + preserv=articlebuf[articlebuf[8]+10]; + articlebuf[articlebuf[8]+10]='\0'; + rb->lcd_putsxy(1,y,articlebuf+10); + //printsim("%s\n",articlebuf+10); + articlebuf[articlebuf[8]+10]=preserv; + } + y+=fontheight; + linecount++; + + renderlen-=articlebuf[8]; + renderoff+=articlebuf[8]; + } + nextlineoff=renderoff; + + linestart=renderoff; + state=STATE_START; + + while (renderlen>0 && y+fontheight < LCD_HEIGHT) { + switch (state) { + case STATE_START: + linestart=renderoff; + switch (articlebuf[renderoff]) { + case '=': + if (linecount==1) { + nextlineoff=renderoff; /* beginning of second line */ + if (norender) return nextlineoff; + } + intdepth=1; + state=STATE_DD; + break; + case MARKUP_LINEFEED: + break; + default: + state=STATE_OTHERTEXT; + break; + } + break; + case STATE_DD: + switch (articlebuf[renderoff]) { + case '=': + intdepth++; + break; + case MARKUP_LINEFEED: + state=STATE_START; /* give up */ + break; + default: + state=STATE_HTEXT; + break; + } + break; + case STATE_DD2: + switch (articlebuf[renderoff]) { + case '=': + extdepth++; + break; + case MARKUP_LINEFEED: + /* final acceptance here */ + if (!norender) { + if (linecount==0) rb->lcd_clear_display(); + int depth=(extdepthutf8seek(articlebuf+linestart+depth+whitey,1); + whitey+=charsize; + } + + rb->lcd_putsxy(1+depth*rb->font_get_width(rb->font_get(FONT_UI),'_'),y, articlebuf+linestart+depth+whitey); + + articlebuf[renderoff-depth]=preserv; + } + linecount++; + y+=fontheight; + state=STATE_START; + break; + default: + state=STATE_HTEXT; /* return to HTEXT, might be an = within a heading */ + break; + } + break; + case STATE_HTEXT: + switch (articlebuf[renderoff]) { + case '=': + extdepth=1; + state=STATE_DD2; + break; + case MARKUP_LINEFEED: + state=STATE_START; /* give up */ + break; + default: + /* continue to accept text within the heading */ + break; + } + break; + case STATE_OTHERTEXT: + switch (articlebuf[renderoff]) { + case MARKUP_LINEFEED: + state=STATE_START; + break; + default: + break; + } + break; + default: + printsim("state error\n"); + } /* end switch (state) */ + charsize = rb->utf8seek(articlebuf+renderoff,1); + renderlen-=charsize; + renderoff+=charsize; + } + + if (!norender) rb->lcd_update(); + + return nextlineoff; +} + +void render_history(int off) { + int i=curhist,j,d; + int x,y,fontheight,t; + char buf[10]; + + rb->lcd_clear_display(); + + y=1; + fontheight = rb->font_get(FONT_UI)->height; + + for (j=1,d=histdepth;d>0 && y+fontheight=(off+1)) { + //printsim("%2d. %s\n",j,hist[i].name); + rb->snprintf(buf,10,"%2d. ",j); + rb->lcd_putsxy(1,y,buf); + rb->lcd_getstringsize(buf,&x,&t); + rb->lcd_putsxy(1+x,y,hist[i].name); + y+=fontheight; + } + i--; + if (i<0) i=HISTORY_LENGTH-1; + } + + rb->lcd_update(); +} + +/* read 2 character ascii hex */ +static int readhex(unsigned char * buf) { + int t=0; + if (buf[0]>='0'&&buf[0]<='9') t=(buf[0]-'0')*16; + else if (buf[0]>='A'&&buf[0]<='F') t=(buf[0]-'A'+10)*16; + else return -1; + + if (buf[1]>='0'&&buf[1]<='9') t+=(buf[1]-'0'); + else if (buf[1]>='A'&&buf[1]<='F') t+=(buf[1]-'A'+10); + else return -1; + + return t; +} + +static bool viewer_init(void) +{ + enum { + MODE_LINK, + MODE_NAVVIEW, + MODE_HISTVIEW, + MODE_NORMAL, + MODE_BOOKVIEW + } mode; + + int linkno; /* currently selected link */ + int navcur; /* current offset for navigation */ + int navnext; /* next offset for navigation mode */ + int navline; /* current line for navigation (important for scrolling up) */ + int histviewoff; /* how far back */ + int bookviewoff; /* how far back */ + int fontheight; + fontheight = rb->font_get(FONT_UI)->height; + + char * target; /* an anchor to seek out */ + + bool prompt=1; /* prompt for article name? */ + bool dofind=1; /* run mwdb_findarticle? */ + curline=0; /* current line */ + + reset_history(); + hist[curhist].curoff=0; /* first article starts at beginning */ + + /* allocate memory */ + wpw_init_mempool(rb,MAINMEMBUF); + inflatebuf=wpw_malloc(MAINMEMBUF,0x13500); + articlebuflen=wpw_available(MAINMEMBUF)>0x32000?0x32000:wpw_available(MAINMEMBUF); + articlebuf=wpw_malloc(MAINMEMBUF,articlebuflen); + + /* initially no name in prompt, subsequently default to previous name */ + rb->memset(hist[curhist].name,0,ARTICLENAMEBUF_LENGTH); + + if (load_status(filename)) { + prompt=0; + dofind=0; + } + + if (load_bookmarks(filename)) { /*UNSURE*/ + } + + target=0; + +loadnewarticle: + if (prompt || dofind) { + if (!mwdb_findarticle(filename,hist[curhist].name,ARTICLENAMEBUF_LENGTH,&hist[curhist].res_lo,&hist[curhist].res_hi,true,prompt,1)) { + /* try case-insensitive match if case-sensitive match fails */ + if (!rb->strlen(hist[curhist].name)) { + /* bailed out */ + + /* automatically go back */ + if (histdepth>1) { + prompt=0; + dofind=0; + advance_history(-1); + + goto loadnewarticle; + } + + return true; + } + if (!mwdb_findarticle(filename,hist[curhist].name,ARTICLENAMEBUF_LENGTH,&hist[curhist].res_lo,&hist[curhist].res_hi,true,0,0)) { + rb->splash(HZ*2, "didn't find \"%s\"",hist[curhist].name); + + /* automatically go back */ + if (histdepth>1) { + prompt=0; + dofind=0; + advance_history(-1); + + goto loadnewarticle; + } + return true; /* No reason to make the plugin fail */ + } + } + } + + prompt=0; + + if (!mwdb_loadarticle(filename,inflatebuf,articlebuf,articlebuflen,&articlelen,hist[curhist].res_lo,hist[curhist].res_hi)) { + return false; /* load error is a problem */ + } + + rb->lcd_clear_display(); + + /* if a target has been specified */ + if (target) { + int i,j; + + /* find headings */ + navcur=-1; + navnext=0; + while (navcur!=navnext) { + navcur=navnext; + navnext=render_outline(navcur,1); + /* navnext will be pointing at the start of the line with the target in it */ + + /* + * Attempt match, this is a bit tricky (and it is probably equally tricky to get + * an anchor pointing to another document in wikicode in the first place). + */ + printsim("attempt to find target: *%s*\n",target); + for (i=0,j=navnext;target[i] && articlebuf[j];) { + printsim("compare %c and %c\n",target[i],articlebuf[j]); + if (target[i]==articlebuf[j]) { + i++; j++; + } else { + printsim("fail %d!=%d\n",target[i],articlebuf[j]); + if (i==0 && (articlebuf[j]=='=' || articlebuf[j]==' ')) j++; /* ignore starting =s, spaces */ + else if (target[i]=='_' && articlebuf[j]==' ') {i++; j++;} /* spaces converted to underscores */ + else if (target[i]=='.') { /* check for escape sequences */ + if (articlebuf[j]==readhex(target+i+1)) {i+=3; j++;} + else break; + } + else break; + } + } + if (target[i]) continue; + while (articlebuf[j]==' ') j++; /* sometimes we see spaces before the closing = */ + if (articlebuf[j]!='=') continue; /* we want the exact heading */ + + /* we have a winner! */ + hist[curhist].curoff=navnext; + } + target=0; + } + + set_article_offset(hist[curhist].curoff); + nextlinestate=render(curlinestate,0,0); + /* get authoritative title name */ + rb->memcpy(hist[curhist].name,articlebuf+10,articlebuf[8]); + hist[curhist].name[(int)(articlebuf[8])]='\0'; + + mode=MODE_NORMAL; + linkno=0; + navcur=0; + navnext=0; + navline=0; + histviewoff=0; + bookviewoff=0; + + /*{ + int i; + for (i=0;i<0x1000;i++) + printf("%c",articlebuf[i]); + }*/ + + int button; + while (!wrquit) { + //button = rb->button_get_w_tmo(HZ/250); + button = rb->button_get(true); + //printf("Button:%d\n",button); + //(1000/HZ) * ticks + if (rb->default_event_handler_ex(button, viewer_exit, NULL)== SYS_USB_CONNECTED) + return PLUGIN_USB_CONNECTED; + switch(button){ + case BUTTON_POWER: + switch (mode) { + case MODE_HISTVIEW: + case MODE_BOOKVIEW: + case MODE_LINK: + case MODE_NAVVIEW: + rb->lcd_clear_display(); + mode=MODE_NORMAL; + nextlinestate=render(curlinestate,0,0); + break; + case MODE_NORMAL: + { + //wrquit=true; + int menuno = menu_init(rb,mww_menu,sizeof(mww_menu)/sizeof(*mww_menu),NULL,NULL,NULL,NULL); + int selection; + int lasthist; + if (menuno<0) return false; + selection=menu_show(menuno); + menu_exit(menuno); + switch (selection) { + case MENU_ATTACHED_USB: + return PLUGIN_USB_CONNECTED; + case MENU_SELECTED_EXIT: + break; + case 0: /* save status */ + save_status(filename); + break; + case 1: /* navigate */ + mode=MODE_NAVVIEW; + navcur=0; + navnext=render_outline(navcur,0); + navline=0; + break; + case 2: /* find similar article */ + lasthist=curhist; + prompt=1; + dofind=1; + + advance_history(1); + rb->strcpy(hist[curhist].name,hist[lasthist].name); + hist[curhist].curoff=0; + + goto loadnewarticle; + break; + case 3: /* find article (blank name) */ + lasthist=curhist; + prompt=1; + dofind=1; + + advance_history(1); + rb->memset(hist[curhist].name,0,ARTICLENAMEBUF_LENGTH); + hist[curhist].curoff=0; + + goto loadnewarticle; + break; + case 4: /* clear hist */ + reset_history(); + rb->memset(hist[curhist].name,0,ARTICLENAMEBUF_LENGTH); + hist[curhist].curoff=0; + prompt=1; + dofind=1; + goto loadnewarticle; + break; + case 5: /* view hist */ + mode=MODE_HISTVIEW; + histviewoff=0; + render_history(histviewoff); + break; + case 6: /* playback control */ + playback_control(rb); + break; + case 7: /* Save Bookmarks */ + save_bookmark(filename); + break; + case 8: /* Bookmarks */ + mode=MODE_BOOKVIEW; + render_bookmarks(0); + break; + case 9: /* Add Bookmark */ + add_bookmark(); + save_bookmark(filename); + break; + case 10: /* exit */ + wrquit=true; + break; + } /* end menu switch */ + if ((mode==MODE_NORMAL) && !wrquit) { + rb->lcd_clear_display(); + nextlinestate=render(curlinestate,0,0); + } + } /* end menu block */ + } /* end mode switch */ + break; + case BUTTON_SELECT: + switch (mode) { + case MODE_NAVVIEW: + set_article_offset(navcur); + nextlinestate=render(curlinestate,0,0); + mode=MODE_NORMAL; + break; + case MODE_NORMAL: + /* enter link select mode */ + mode=MODE_LINK; + linkno=1; + nextlinestate=render(curlinestate,0,linkno); + if (lastlinkcount==0) mode=MODE_NORMAL; + break; + case MODE_LINK: + /* load a new article */ + advance_history(1); + readlink(curlinestate,linkno,hist[curhist].name,ARTICLENAMEBUF_LENGTH); + if ((target=rb->strrchr(hist[curhist].name,'#'))) { + /* cut the target name off the end of the string */ + target[0]='\0'; + target++; /* to point at the name of the target */ + } + hist[curhist].curoff=0; + dofind=1; + goto loadnewarticle; + case MODE_HISTVIEW: + /* jump back */ + if (histviewoff>0) { + int i; + for (i=0;isplash(HZ*2, "error"); + } + else + { + int booki; + booki=bookdepth-bookviewoff-1; + curhist++; + histdepth++; + rb->strcpy(hist[curhist].name,book[booki].name); + hist[curhist].curoff=book[booki].curoff; + hist[curhist].res_lo=book[booki].res_lo; + hist[curhist].res_hi=book[booki].res_hi; + dofind=0; + mode=MODE_NORMAL; + goto loadnewarticle; + } + nextlinestate=render(curlinestate,0,0); + mode=MODE_NORMAL; + break; + default: + break; + } /* end mode switch */ + break; +#ifdef BUTTON_SCROLL_FWD + case BUTTON_SCROLL_FWD: + case BUTTON_SCROLL_FWD|BUTTON_REPEAT: +#else + case BUTTON_SCROLL_DOWN: + case BUTTON_SCROLL_DOWN|BUTTON_REPEAT: + case BUTTON_DOWN: + case BUTTON_DOWN|BUTTON_REPEAT: +#endif + switch (mode) { + case MODE_NAVVIEW: + if (navnext!=navcur) { + navline++; + } + navcur=navnext; + navnext=render_outline(navcur,0); + break; + case MODE_LINK: + /* select next link */ + if (linkno0) { + navline--; + navnext=0; + for (i=0;i1) { + linkno--; + nextlinestate=render(curlinestate,0,linkno); + } + break; + case MODE_NORMAL: + if (button==BUTTON_UP) { /*scroll up page*/ + advance_scrollback((1-(LCD_HEIGHT/fontheight)),1); + } + else { /* scroll up */ + advance_scrollback(-1,1); + } + break; + case MODE_HISTVIEW: + if (histviewoff>0) { + histviewoff--; + render_history(histviewoff); + } + break; + case MODE_BOOKVIEW: + if (bookviewoff>0) { + bookviewoff--; + render_bookmarks(bookviewoff); + } + break; + } /* end mode switch */ + break; + case BUTTON_LEFT: /* go back */ + switch (mode) { + case MODE_NORMAL: + if (histdepth>1) { + advance_history(-1); + dofind=0; + goto loadnewarticle; + } + break; + case MODE_BOOKVIEW: + remove_bookmark(bookviewoff); + bookviewoff=0; + render_bookmarks(bookviewoff); + break; + default: + break; + } /* end mode switch */ + break; + case BUTTON_RIGHT: /* go forward */ + switch (mode) { + case MODE_NORMAL: + if (hist[(curhist+1)].curoff>0) { + advance_history(1); + dofind=0; + bookviewoff=0; + goto loadnewarticle; + } + break; + case MODE_BOOKVIEW: + if (load_bookmarks(filename)) + { + render_bookmarks(bookviewoff); + } + break; + default: + break; + } /* end mode switch */ + break; + + case BUTTON_REC: /*record line*/ + case BUTTON_REC|BUTTON_REPEAT: + switch (mode) { + case MODE_NORMAL: + record_flag=1; + advance_scrollback(1,1); + break; + case MODE_BOOKVIEW: + save_bookmark(filename); + break; + default: + break; + } /* end mode switch */ + break; + + default: + break; + } /* end button switch */ + } /* end main loop */ + return true; +} + +static bool check_dir(char *folder) +{ + DIR *dir = rb->opendir(folder); + if (!dir && rb->strcmp(folder, "/")) + { + int rc = rb->mkdir(folder); + if(rc < 0) + return false; + return true; + } + rb->closedir(dir); + return true; +} + +enum plugin_status plugin_start(struct plugin_api* api, void* file) +{ + rb = api; + rb->backlight_set_timeout(1); /*Turn off backlight timeout*/ + check_dir("/wiki"); + if (!file) + return PLUGIN_ERROR; + filename = file; + filename[rb->strlen(filename)-4]='\0'; + + rb->lcd_set_drawmode(DRMODE_SOLID); + + if (!viewer_init()) + return PLUGIN_ERROR; + + viewer_exit(NULL); + rb->backlight_set_timeout(rb->global_settings->backlight_timeout); + /*Turn on backlight timeout*/ + return PLUGIN_OK; +} +// kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle; Index: rockbox/apps/plugins/mww/btsearch.c =================================================================== --- rockbox/apps/plugins/mww/btsearch.c (revision 0) +++ rockbox/apps/plugins/mww/btsearch.c (revision 0) @@ -0,0 +1,115 @@ +/*#include */ +/*#include */ +#include "plugin.h" +#include "btsearch.h" +#include +#define KEY_MAXLEN 512 + +size_t sf_read(int fd, void *buf, size_t count) +{ + ssize_t n; + + do { + n = read(fd, buf, count); + } while (n < 0&&n!=-1); +/* if(n==-1) + LOGF("RDRR");*/ + return n; +} + +signed char utf8strcnmp(const unsigned char *s1, const unsigned char *s2,uint16_t n1,uint16_t n2,const bool casesense){ + unsigned short c1,c2; + const unsigned char *s1p,*s2p; + s1p=s1; + s2p=s2; + for(;;){ + if(s1p-s1==n1){ + if(n1==n2&&n2==s2p-s2) return 0; + else return -1; + } + if(s2p-s2==n2){ + if(n1==n2&&n1==s1p-s1) return 0; + else return 1; + } + s1p=utf8decode(s1p,&c1); + s2p=utf8decode(s2p,&c2); + if(c1==' ')c1='_'; + if(c2==' ')c2='_'; + //if(s1p-s1==1&&s2p-s2==1&&c1<128&&c2<128){ + if(!casesense && c1<128&&c2<128){ + c1=tolower(c1); + c2=tolower(c2); + } + if(c1c2) return 1; + } + return 0; +} + +/* Decode 1 UTF-8 char and return a pointer to the next char. */ +void search_btree(int file,const char* key,uint16_t rkeylen, uint32_t globoffs, uint32_t* res_lo,uint32_t* res_hi,const bool casesense) { + unsigned char nd_key[KEY_MAXLEN]; + uint8_t node_flags; + uint16_t node_nr_active,i,keylen; + uint32_t chldptr; + uint32_t dtaptr_lo,dtaptr_hi; + sf_read(file,&node_flags,1); + sf_read(file,&node_nr_active,2); + node_nr_active=letoh16(node_nr_active); + if(node_nr_active<1){//error + *res_lo=*res_hi=0; + return; + } + for(i=0;istrlen(nd_key)!=keylen){ + *res_lo=*res_hi=0; + LOGF("WrongKL\n"); + return; + } + + if(keylen-KEY_MAXLEN>0){ + rb->lseek(file,keylen-((keylen0){ + continue; + } + if(utf8strcnmp(((const unsigned char*)key),((const unsigned char*)nd_key),rkeylen,keylen,casesense)==0) { + *res_lo=dtaptr_lo; + *res_hi=dtaptr_hi; + return; + } + if(chldptr==0||node_flags==1){ + *res_lo=*res_hi=0; + return; + } + rb->lseek(file,globoffs+chldptr,0); + search_btree(file,key,rkeylen,globoffs,res_lo,res_hi,casesense); + return; + } + if(node_flags!=1){//node not leaf + sf_read(file, &chldptr,4); + chldptr=letoh32(chldptr); + if(chldptr==0){//leaf + *res_lo=*res_hi=0; + return; + } + rb->lseek(file,globoffs+chldptr,0); + search_btree(file,key,rkeylen,globoffs,res_lo,res_hi,casesense); + return; + } + *res_lo=*res_hi=0; + return; +} Index: rockbox/apps/plugins/mww/Makefile =================================================================== --- rockbox/apps/plugins/mww/Makefile (revision 0) +++ rockbox/apps/plugins/mww/Makefile (revision 0) @@ -0,0 +1,115 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id: Makefile,v 1.5 2006-10-23 22:33:36 amiconn Exp $ +# + +INCLUDES = -I$(APPSDIR) -I.. -I. $(TARGET_INC) -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ + -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) -I$(BUILDDIR) +CFLAGS = $(INCLUDES) $(GCCOPTS) -O2 $(TARGET) $(EXTRA_DEFINES) \ + -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN + +ifdef APPEXTRA + INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA))) +endif + +LINKFILE := $(OBJDIR)/link.lds +DEPFILE = $(OBJDIR)/dep-mww + +# This sets up 'SRC' based on the files mentioned in SOURCES +include $(TOOLSDIR)/makesrc.inc + +SOURCES = $(SRC) +OBJS2 := $(SRC:%.c=$(OBJDIR)/%.o) +OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2)) +DIRS = . + +LDS := ../plugin.lds +OUTPUT = $(OUTDIR)/mww.rock + +all: $(OUTPUT) + +ifndef SIMVER +$(OBJDIR)/mww.elf: $(OBJS) $(LINKFILE) + @echo "LD $(notdir $@)" + @$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \ + -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/mww.map + +$(OUTPUT): $(OBJDIR)/mww.elf + @echo "OBJCOPY $(notdir $@)" + @$(OC) -O binary $< $@ +else + +ifeq ($(SIMVER), x11) +################################################### +# This is the X11 simulator version + +$(OUTPUT): $(OBJS) + @echo "LD $(notdir $@)" + @$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif + +else # end of x11-simulator +ifeq ($(SIMVER), sdl) +################################################### +# This is the SDL simulator version + +$(OUTPUT): $(OBJS) + @echo "LD $(notdir $@)" + @$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif + +else # end of sdl-simulator +################################################### +# This is the win32 simulator version +DLLTOOLFLAGS = --export-all +DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin + +$(OUTPUT): $(OBJS) + @echo "DLL $(notdir $@)" + @$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS) + @$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \ + $(BUILDDIR)/libplugin.a -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif +endif # end of win32-simulator +endif +endif # end of simulator section + + +include $(TOOLSDIR)/make.inc + +# MEMORYSIZE should be passed on to this makefile with the chosen memory size +# given in number of MB +$(LINKFILE): $(LDS) + @echo "build $(notdir $@)" + @cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) \ + $(DEFINES) -E -P - >$@ + +clean: + @echo "cleaning mediawikiviewer" + @rm -rf $(OBJDIR)/mww + @rm -f $(OBJDIR)/mww.* $(DEPFILE) + +-include $(DEPFILE) + Index: rockbox/apps/plugins/SUBDIRS =================================================================== --- rockbox/apps/plugins/SUBDIRS (revision 14450) +++ rockbox/apps/plugins/SUBDIRS (working copy) @@ -18,6 +18,7 @@ chessbox sudoku reversi +mww #endif /* For all 2bpp and colour targets */