Index: apps/plugins/CATEGORIES =================================================================== --- apps/plugins/CATEGORIES (Revision 26945) +++ apps/plugins/CATEGORIES (Arbeitskopie) @@ -122,6 +122,7 @@ wavplay,viewers wavrecord,apps wavview,viewers +wikiviewer,viewers wormlet,games xobox,games zxbox,viewers Index: apps/plugins/wikiviewer/mallocer.c =================================================================== --- apps/plugins/wikiviewer/mallocer.c (Revision 0) +++ apps/plugins/wikiviewer/mallocer.c (Revision 0) @@ -0,0 +1,103 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Frederik M.J. Vestre + * Copyright (C) 2006 Adam Gashlin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +/* + Based on the malloc in codeclib Copyright (C) 2005 Dave Chapman + */ + +#include "mallocer.h" + +unsigned char* mallocbuf[MEMPOOL_MAX]; +long mem_ptr[MEMPOOL_MAX]; +size_t bufsize[MEMPOOL_MAX]; + +#include "plugin.h" + +int wpw_init_mempool(unsigned char mempool) +{ + mem_ptr[mempool] = 0; + mallocbuf[mempool] = (unsigned char *)rb->plugin_get_buffer(&bufsize[mempool]); + return 0; +} + +int wpw_init_mempool_pdm(unsigned char mempool, + unsigned char* mem,long memsize) +{ + mem_ptr[mempool] = 0; + mallocbuf[mempool] = mem; + bufsize[mempool]=memsize; + return 0; +} + +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; + + 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 */ + + 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; + + rb->memset(x,0,nmemb*size); + 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: apps/plugins/wikiviewer/mwdb.h =================================================================== --- apps/plugins/wikiviewer/mwdb.h (Revision 0) +++ apps/plugins/wikiviewer/mwdb.h (Revision 0) @@ -0,0 +1,43 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef MWDB_H +#define MWDB_H +#include + + +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: apps/plugins/wikiviewer/wikiviewer.make =================================================================== --- apps/plugins/wikiviewer/wikiviewer.make (Revision 0) +++ apps/plugins/wikiviewer/wikiviewer.make (Revision 0) @@ -0,0 +1,21 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id: $ +# + +WIKIVIEWER_SRCDIR := $(APPSDIR)/plugins/wikiviewer +WIKIVIEWER_BUILDDIR := $(BUILDDIR)/apps/plugins/wikiviewer + +ROCKS += $(WIKIVIEWER_BUILDDIR)/wikiviewer.rock + +WIKIVIEWER_SRC := $(call preprocess, $(WIKIVIEWER_SRCDIR)/SOURCES) +WIKIVIEWER_OBJ := $(call c2obj, $(WIKIVIEWER_SRC)) + +# add source files to OTHER_SRC to get automatic dependencies +OTHER_SRC += $(WIKIVIEWER_SRC) + +$(WIKIVIEWER_BUILDDIR)/wikiviewer.rock: $(WIKIVIEWER_OBJ) Index: apps/plugins/wikiviewer/inflate.c =================================================================== --- apps/plugins/wikiviewer/inflate.c (Revision 0) +++ apps/plugins/wikiviewer/inflate.c (Revision 0) @@ -0,0 +1,1149 @@ +/* + * gunzip implementation for wikiviewer (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 +#ifndef NULL +#define NULL 0 +#endif +#define ENABLE_DESKTOP 0 +#define USE_DESKTOP(...) +#include "mallocer.h" +#include "bbfuncs.h" +#include "inflate.h" +#include "mallocer.h" + +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 HUFT_MMP1 8 +#define HUFT_MMP2 9 + +static int gunzip_src_fd; +static 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; + +/* 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 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 +}; + +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) + { + } + + 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 */ + rb->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)); + if(q==0) + 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 */ + + /* bits to dump before this table */ + r.b = (unsigned char) (w - ws[htl - 1]); + 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[] + */ +static 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); + 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) + */ + { + rb->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; + + 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); + 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); + } + + 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); + 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"); + } + 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; +} + +static int inflate_get_next_window_method = -1; /* Method == -1 for stored, -2 + for codes */ +static int inflate_get_next_window_e = 0; +static 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) + { + 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: + error_die("inflate error"); + } + + if (ret == 1) + { + calculate_gunzip_crc(); + 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 */ +static 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; +} + +static void inflate_cleanup(void) +{ + /* free(bytebuffer); */ +} + +USE_DESKTOP(long long) static int +inflate_unzip(int in,char* outbuffer,uint32_t outbuflen) +{ + USE_DESKTOP(long long total = 0; ) + typedef void (*sig_type)(int); + + /* Allocate all global buffers (for DYN_ALLOC option) */ + 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 = ~0; + + /* Allocate space for buffer */ + while(1) + { + int ret = inflate_get_next_window(); + if((signed int)outbuflen-(signed int)gunzip_outbuf_count<0) + { + error_msg("write_error"); + return -1; + } + + rb->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; + } + + /* 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) static 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"); + 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"); + 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*/ + huftbuffer1=membuf; + huftbuffer2=membuf+0x2A00; + gunzip_window=membuf+0x2A00+0xA00; + bytebuffer=membuf+0x2A00+0xA00+0x8000; + wpw_init_mempool_pdm(HUFT_MMP1,(unsigned char*)huftbuffer1,0x2A00); + wpw_init_mempool_pdm(HUFT_MMP2,(unsigned char*)huftbuffer2,0xA00); + + src_fd = rb->open(inflenme, O_RDONLY); + if(src_fd==-1) + return 0; + + 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"); + exitcode = -1; + } + + if (status < 0) + { + error_msg("error inflating"); + exitcode = -1; + } + } + else + { + error_msg("invalid magic"); + exitcode = -1; + } + + inflate_cleanup(); + wpw_destroy_mempool(HUFT_MMP1); + wpw_destroy_mempool(HUFT_MMP2); + rb->close(src_fd); + + if(exitcode==-1) + return 0; + + return ifl_total; +} Index: apps/plugins/wikiviewer/bbfuncs.c =================================================================== --- apps/plugins/wikiviewer/bbfuncs.c (Revision 0) +++ apps/plugins/wikiviewer/bbfuncs.c (Revision 0) @@ -0,0 +1,146 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" +#include "lib/pluginlib_exit.h" + +void error_die(const char* msg) +{ + rb->splash(3 * HZ, msg); + exit(0); +} + +void error_msg(const char* msg) +{ + (void)msg; +} + +size_t safe_read(int fd, void *buf, size_t count) +{ + ssize_t n; + + do { + n = rb->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) +{ + unsigned char tmp; + + xread(fd, &tmp, 1); + + return tmp; +} + +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); + } +} Index: apps/plugins/wikiviewer/SOURCES =================================================================== --- apps/plugins/wikiviewer/SOURCES (Revision 0) +++ apps/plugins/wikiviewer/SOURCES (Revision 0) @@ -0,0 +1,6 @@ +wikiviewer.c +mwdb.c +mallocer.c +inflate.c +btsearch.c +bbfuncs.c Index: apps/plugins/wikiviewer/mallocer.h =================================================================== --- apps/plugins/wikiviewer/mallocer.h (Revision 0) +++ apps/plugins/wikiviewer/mallocer.h (Revision 0) @@ -0,0 +1,34 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#define MEMPOOL_MAX 10 +#include +#include "plugin.h" + +int wpw_init_mempool(unsigned char mempool); +int wpw_init_mempool_pdm(unsigned char mempool, + unsigned char* mem,long memsize); + +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: apps/plugins/wikiviewer/wikiviewer.c =================================================================== --- apps/plugins/wikiviewer/wikiviewer.c (Revision 0) +++ apps/plugins/wikiviewer/wikiviewer.c (Revision 0) @@ -0,0 +1,1943 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Frederik M.J. Vestre + * Copyright (C) 2006 Adam Gashlin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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/pluginlib_exit.h" +#if LCD_DEPTH > 1 + #define COLORLINKS +#endif + +PLUGIN_HEADER + +/* keymappings */ + +#if (CONFIG_KEYPAD == IPOD_4G_PAD) +#define WIKIVIEWER_MENU BUTTON_MENU +#define WIKIVIEWER_SELECT BUTTON_SELECT +#define WIKIVIEWER_STOP_RECORD (BUTTON_SELECT|BUTTON_REPEAT) +#define WIKIVIEWER_FWD BUTTON_SCROLL_FWD +#define WIKIVIEWER_FWD_REPEAT (BUTTON_SCROLL_FWD|BUTTON_REPEAT) +#define WIKIVIEWER_BACK BUTTON_SCROLL_BACK +#define WIKIVIEWER_BACK_REPEAT (BUTTON_SCROLL_BACK|BUTTON_REPEAT) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +#define WIKIVIEWER_RECORD BUTTON_PLAY +#define WIKIVIEWER_RECORD_REPEAT (BUTTON_PLAY|BUTTON_REPEAT) + +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ + (CONFIG_KEYPAD == IRIVER_H300_PAD) +#define WIKIVIEWER_MENU BUTTON_OFF +#define WIKIVIEWER_SELECT BUTTON_SELECT +#define WIKIVIEWER_STOP_RECORD (BUTTON_REC|BUTTON_MODE) +#define WIKIVIEWER_FWD BUTTON_DOWN +#define WIKIVIEWER_FWD_REPEAT (BUTTON_DOWN|BUTTON_MODE) +#define WIKIVIEWER_BACK BUTTON_UP +#define WIKIVIEWER_BACK_REPEAT (BUTTON_UP|BUTTON_MODE) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +#define WIKIVIEWER_RECORD BUTTON_REC +#define WIKIVIEWER_RECORD_REPEAT (BUTTON_REC|BUTTON_MODE) + +#elif (CONFIG_KEYPAD == GIGABEAT_PAD) +#define WIKIVIEWER_MENU BUTTON_MENU +#define WIKIVIEWER_SELECT BUTTON_SELECT +#define WIKIVIEWER_STOP_RECORD (BUTTON_SELECT|BUTTON_REPEAT) +#define WIKIVIEWER_FWD BUTTON_DOWN +#define WIKIVIEWER_FWD_REPEAT (BUTTON_DOWN|BUTTON_REPEAT) +#define WIKIVIEWER_BACK BUTTON_UP +#define WIKIVIEWER_BACK_REPEAT (BUTTON_UP|BUTTON_REPEAT) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +#define WIKIVIEWER_RECORD BUTTON_A +#define WIKIVIEWER_RECORD_REPEAT (BUTTON_A|BUTTON_REPEAT) + +#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) +#define WIKIVIEWER_MENU BUTTON_MENU +#define WIKIVIEWER_SELECT BUTTON_SELECT +#define WIKIVIEWER_STOP_RECORD (BUTTON_SELECT|BUTTON_REPEAT) +#define WIKIVIEWER_FWD BUTTON_DOWN +#define WIKIVIEWER_FWD_REPEAT (BUTTON_DOWN|BUTTON_REPEAT) +#define WIKIVIEWER_BACK BUTTON_UP +#define WIKIVIEWER_BACK_REPEAT (BUTTON_UP|BUTTON_REPEAT) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +#define WIKIVIEWER_RECORD BUTTON_BACK +#define WIKIVIEWER_RECORD_REPEAT (BUTTON_BACK|BUTTON_REPEAT) + +#elif (CONFIG_KEYPAD == MROBE100_PAD) +#define WIKIVIEWER_MENU BUTTON_MENU +#define WIKIVIEWER_SELECT BUTTON_SELECT +#define WIKIVIEWER_STOP_RECORD (BUTTON_SELECT|BUTTON_REPEAT) +#define WIKIVIEWER_FWD BUTTON_DOWN +#define WIKIVIEWER_FWD_REPEAT (BUTTON_DOWN|BUTTON_REPEAT) +#define WIKIVIEWER_BACK BUTTON_UP +#define WIKIVIEWER_BACK_REPEAT (BUTTON_UP|BUTTON_REPEAT) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +#define WIKIVIEWER_RECORD BUTTON_DISPLAY +#define WIKIVIEWER_RECORD_REPEAT (BUTTON_DISPLAY|BUTTON_REPEAT) + +#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) +#define WIKIVIEWER_MENU BUTTON_REC +#define WIKIVIEWER_SELECT BUTTON_SELECT +#define WIKIVIEWER_STOP_RECORD (BUTTON_SELECT|BUTTON_REPEAT) +#define WIKIVIEWER_FWD BUTTON_DOWN +#define WIKIVIEWER_FWD_REPEAT (BUTTON_DOWN|BUTTON_REPEAT) +#define WIKIVIEWER_BACK BUTTON_UP +#define WIKIVIEWER_BACK_REPEAT (BUTTON_UP|BUTTON_REPEAT) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +#define WIKIVIEWER_RECORD BUTTON_PLAY +#define WIKIVIEWER_RECORD_REPEAT (BUTTON_PLAY|BUTTON_REPEAT) + +#elif (CONFIG_KEYPAD == SANSA_C200_PAD) +#define WIKIVIEWER_MENU BUTTON_POWER +#define WIKIVIEWER_SELECT BUTTON_SELECT +#define WIKIVIEWER_STOP_RECORD (BUTTON_SELECT|BUTTON_REPEAT) +#define WIKIVIEWER_FWD BUTTON_DOWN +#define WIKIVIEWER_FWD_REPEAT (BUTTON_DOWN|BUTTON_REPEAT) +#define WIKIVIEWER_FWD2 BUTTON_VOL_UP +#define WIKIVIEWER_FWD2_REPEAT (BUTTON_VOL_UP|BUTTON_REPEAT) +#define WIKIVIEWER_BACK BUTTON_UP +#define WIKIVIEWER_BACK_REPEAT (BUTTON_UP|BUTTON_REPEAT) +#define WIKIVIEWER_BACK2 BUTTON_VOL_DOWN +#define WIKIVIEWER_BACK2_REPEAT (BUTTON_VOL_DOWN|BUTTON_REPEAT) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +#define WIKIVIEWER_RECORD BUTTON_REC +#define WIKIVIEWER_RECORD_REPEAT (BUTTON_REC|BUTTON_REPEAT) + +#elif (CONFIG_KEYPAD == SANSA_E200_PAD) +#define WIKIVIEWER_MENU BUTTON_POWER +#define WIKIVIEWER_SELECT BUTTON_SELECT +#define WIKIVIEWER_STOP_RECORD (BUTTON_SELECT|BUTTON_REPEAT) +#define WIKIVIEWER_FWD BUTTON_DOWN +#define WIKIVIEWER_FWD_REPEAT (BUTTON_DOWN|BUTTON_REPEAT) +#define WIKIVIEWER_FWD2 BUTTON_SCROLL_FWD +#define WIKIVIEWER_FWD2_REPEAT (BUTTON_SCROLL_FWD|BUTTON_REPEAT) +#define WIKIVIEWER_BACK BUTTON_UP +#define WIKIVIEWER_BACK_REPEAT (BUTTON_UP|BUTTON_REPEAT) +#define WIKIVIEWER_BACK2 BUTTON_SCROLL_BACK +#define WIKIVIEWER_BACK2_REPEAT (BUTTON_SCROLL_BACK|BUTTON_REPEAT) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +#define WIKIVIEWER_RECORD BUTTON_REC +#define WIKIVIEWER_RECORD_REPEAT (BUTTON_REC|BUTTON_REPEAT) + +#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) +#define WIKIVIEWER_MENU BUTTON_HOME +#define WIKIVIEWER_SELECT BUTTON_SELECT +/* #define WIKIVIEWER_STOP_RECORD (BUTTON_SELECT|BUTTON_REPEAT) */ +#define WIKIVIEWER_FWD BUTTON_DOWN +#define WIKIVIEWER_FWD_REPEAT (BUTTON_DOWN|BUTTON_REPEAT) +#define WIKIVIEWER_FWD2 BUTTON_SCROLL_FWD +#define WIKIVIEWER_FWD2_REPEAT (BUTTON_SCROLL_FWD|BUTTON_REPEAT) +#define WIKIVIEWER_BACK BUTTON_UP +#define WIKIVIEWER_BACK_REPEAT (BUTTON_UP|BUTTON_REPEAT) +#define WIKIVIEWER_BACK2 BUTTON_SCROLL_BACK +#define WIKIVIEWER_BACK2_REPEAT (BUTTON_SCROLL_BACK|BUTTON_REPEAT) +#define WIKIVIEWER_PREV BUTTON_LEFT +#define WIKIVIEWER_NEXT BUTTON_RIGHT +/* #define WIKIVIEWER_RECORD (BUTTON_SELECT|BUTTON_REPEAT) */ +/* #define WIKIVIEWER_RECORD_REPEAT (BUTTON_HOME|BUTTON_REPEAT) */ + +#elif (CONFIG_KEYPAD == ONDAVX747_PAD) +#define WIKIVIEWER_MENU BUTTON_POWER + +#endif + +#ifdef HAVE_TOUCHSCREEN +#ifndef WIKIVIEWER_SELECT +#define WIKIVIEWER_SELECT BUTTON_CENTER +#endif +#ifndef WIKIVIEWER_MENU +#define WIKIVIEWER_MENU BUTTON_TOPLEFT +#endif +#ifndef WIKIVIEWER_FWD +#define WIKIVIEWER_FWD BUTTON_BOTTOMMIDDLE +#define WIKIVIEWER_FWD_REPEAT (BUTTON_BOTTOMMIDDLE|BUTTON_REPEAT) +#endif +#ifndef WIKIVIEWER_BACK +#define WIKIVIEWER_BACK BUTTON_TOPMIDDLE +#define WIKIVIEWER_BACK_REPEAT (BUTTON_TOPMIDDLE|BUTTON_REPEAT) +#endif +#ifndef WIKIVIEWER_PREV +#define WIKIVIEWER_PREV BUTTON_MIDLEFT +#endif +#ifndef WIKIVIEWER_NEXT +#define WIKIVIEWER_NEXT BUTTON_MIDRIGHT +#endif +#endif + +#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 + + +/* change on any change to file format, histstate */ +#define SAVE_FILE_VERSION_MAGIC 0x12340004 + +static bool wrquit=false; +static char filename[MAX_PATH+1]; /* name of database, without extension */ + +#define MAINMEMBUF 0 + + +static void *inflatebuf; /* heap for gunzip */ +static char *articlebuf; /* destination for uncompressed article */ +static uint32_t articlebuflen=0; /* size of the article buffer */ +static uint32_t articlelen=0; /* used size of the article buffer */ + +static 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 */ +static 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 + +static int curlinehist,linehistdepth; +static int curline; +static 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.renderoffsnprintf(fnbuf,MAX_PATH,"%s.wwb",filename); + fd = rb->open(fnbuf, O_RDONLY); + + if (fd<0) + goto err; + + if (rb->read(fd,&magic,sizeof(magic))<=0) + goto err; + + if (magic!=SAVE_FILE_VERSION_MAGIC) + goto err; + + if (rb->read(fd,&booki,sizeof(booki))<=0) + goto err; + + if (booki<=0) + goto err; + + for (i=0; iread(fd,book+i,sizeof(struct bookstate))<=0) + goto err; + } + + bookdepth = booki; + + ret = 1; + +err: + if(fd >= 0) + rb->close(fd); + + return ret; +} + +static 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); +} + +static 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++; +} + +static 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(); +} + +static 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--; +} + +static 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); +} + +static int load_status(const char * filename) +{ + char fnbuf[MAX_PATH+1]; + int fd, i, histi, ret = 0; + uint32_t magic=0; + + rb->snprintf(fnbuf,MAX_PATH,"%s.wws",filename); + fd = rb->open(fnbuf, O_RDONLY); + if (fd<0) + goto err; + + if (rb->read(fd,&magic,sizeof(magic))<=0) + goto err; + + if (magic!=SAVE_FILE_VERSION_MAGIC) + goto err; + + if (rb->read(fd,&histi,sizeof(histi))<=0) + goto err; + + if (histi<=0) + goto err; + + for (i=0; iread(fd,hist+i,sizeof(struct histstate))<=0) + goto err; + } + + histdepth=histi; + curhist=i-1; + + ret = 1; + +err: + if(fd >= 0) + rb->close(fd); + + return ret; +} + +static void set_article_offset(int32_t off) +{ + /* go to offset off in current article */ + + reset_scrollback(); + curline=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); + + while (!nextlinestate.eof && hist[curhist].curoff1) + for (i=0; i0) + { + /* if we have records to fall back on */ + linehistdepth--; + 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 /* a==1 */ + /* scroll forwards one line */ + if (!nextlinestate.eof || ((record_flag==1) && (end_of_file==0))) + { + 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--; + } +} + +static int iswhitespace(uint16_t c) +{ + return (c==' ' || c=='\n'); /* what about tab character? */ +} + +static int islinebreak(uint16_t c) +{ + return (c=='\n'); +} + +/* 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*/ + + end_of_file=0; + +#ifdef COLORLINKS + uint8_t em[LCD_WIDTH]; /* type of emphasis for this pixel */ + unsigned lastcol=0; + 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; + /* if the last character was whitespace we'll ignore subsequent whitespace + */ + int lastwaswhitespace; + + 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; + + /* prevent whitespace from appearing at the beginning of a line */ + lastwaswhitespace=1; + + /* 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: + cur.inlink=1; + cur.linknameoff=cur.renderoff; + cur.renderlen--; + cur.renderoff++; + break; + + case MARKUP_ENDLINK: + 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; + + if (first<1) + { + if (record_flag==1) + { + 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 + { + if (record_stop_flag) + { + rb->write(fd1,"\n\r",2); + record_stop_flag=false; + } + + rb->write(fd1,(unsigned char *)last_line,last_line_i); + if (record_linebreak>0) + rb->write(fd1,"\n",2); + else + rb->write(fd1," ",1); + + rb->close(fd1); + } + } + + last_line_i=i; + rb->memcpy(last_line,buf,(last_line_i)); + if (islinebreak(ucs)) + record_linebreak=1; + else + record_linebreak=0; + } + + first++; + + buf[(i<=LINEBUFLEN) ? i : LINEBUFLEN]='\0'; + rb->lcd_putsxy(1,y, (unsigned char *)buf); + 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) + { + if (first<2) + end_of_file=1; + + cur.eof=1; + nextline.eof=1; + while ((y+fontheight) < LCD_HEIGHT) + { + rb->lcd_putsxy(1,y," "); + y+=fontheight; + } + } + + 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) + /* 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; + int extdepth=0; + int 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) + { + preserv=articlebuf[articlebuf[8]+10]; + articlebuf[articlebuf[8]+10]='\0'; + rb->lcd_putsxy(1,y,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; + if(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: + /* return to HTEXT, might be an = within a heading */ + state=STATE_HTEXT; + 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; + } /* end switch (state) */ + + charsize = rb->utf8seek(articlebuf+renderoff,1); + renderlen-=charsize; + renderoff+=charsize; + } + + if (!norender) + rb->lcd_update(); + + return nextlineoff; +} + +static 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)) + { + 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(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); + +#ifdef HAVE_TOUCHSCREEN + rb->touchscreen_set_mode(TOUCHSCREEN_POINT); +#endif + + 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; /* few lines up */ + } + + return true; + } + + if (!mwdb_findarticle(filename,hist[curhist].name, + ARTICLENAMEBUF_LENGTH,&hist[curhist].res_lo, + &hist[curhist].res_hi,true,0,0)) + { + rb->splashf(HZ*2, "didn't find \"%s\"",hist[curhist].name); + + /* automatically go back */ + if (histdepth>1) + { + if (prompt==0) + { + prompt=0; + dofind=0; + advance_history(-1); + } + + goto loadnewarticle; /* few lines up */ + } + + 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). + */ + for (i=0,j=navnext; target[i] && articlebuf[j]; ) + { + if (target[i]==articlebuf[j]) + { + i++; j++; + } + else + { + 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 button; + while (!wrquit) + { + button = rb->button_get(true); + + if (rb->default_event_handler_ex(button, viewer_exit, NULL)== + SYS_USB_CONNECTED) + return PLUGIN_USB_CONNECTED; + +#ifdef HAVE_TOUCHSCREEN + if (button & BUTTON_TOUCHSCREEN) + { + static int prevY = 0; + short x, y; + int fontheight = rb->font_get(FONT_UI)->height; + x = rb->button_get_data() >> 16; + y = rb->button_get_data() & 0xFFFF; + + if(button & BUTTON_REL) + prevY = 0; + else + { + if (prevY != 0) + { + if (mode == MODE_NORMAL) + { + int pageDelta = (y - prevY) / fontheight; + advance_scrollback(-pageDelta, 1); + } + } + prevY = y; + } + } +#endif + + switch(button) + { + case WIKIVIEWER_MENU: + switch (mode) + { + case MODE_BOOKVIEW: + save_bookmark(filename); + case MODE_HISTVIEW: + case MODE_LINK: + case MODE_NAVVIEW: + rb->lcd_clear_display(); + mode=MODE_NORMAL; + nextlinestate=render(curlinestate,0,0); + break; + case MODE_NORMAL: + { + /* wrquit=true; */ + MENUITEM_STRINGLIST(main_menu, "Wikiviewer Menu", NULL, + "Save History", + "Navigate", + "Find Similar Article", + "Find Article", + "Clear History", + "View History", + "Show Playback Menu", + "Bookmarks", + "Add Bookmark", + "Exit"); + + int selection = 0; + int lasthist; + switch (rb->do_menu(&main_menu, &selection, NULL, false)) + { + case MENU_ATTACHED_USB: + return PLUGIN_USB_CONNECTED; + + 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(NULL); + break; + + case 7: /* Bookmarks */ + mode=MODE_BOOKVIEW; + render_bookmarks(0); + break; + + case 8: /* Add Bookmark */ + add_bookmark(); + save_bookmark(filename); + break; + + case 9: /* 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 WIKIVIEWER_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; /* ~line 1165 */ + + case MODE_HISTVIEW: + /* jump back */ + if (histviewoff>0) + { + int i; + for (i=0; isplash(HZ*2, "error"); + else + { + save_bookmark(filename); + 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; /* ~line 1165 */ + } + + nextlinestate=render(curlinestate,0,0); + mode=MODE_NORMAL; + break; + + default: + break; + } /* end mode switch */ + break; + +#ifdef WIKIVIEWER_STOP_RECORD + case WIKIVIEWER_STOP_RECORD: + switch (mode) + { + case MODE_NORMAL: /*reset recording flag*/ + record_stop_flag=true; + break; + default: + break; + } /* end mode switch */ + break; +#endif + + case WIKIVIEWER_FWD: + case WIKIVIEWER_FWD_REPEAT: +#ifdef WIKIVIEWER_FWD2 + case WIKIVIEWER_FWD2: + case WIKIVIEWER_FWD2_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: +#ifdef WIKIVIEWER_BACK2 + if (button==WIKIVIEWER_BACK2) /*scroll up page*/ + advance_scrollback((1-(LCD_HEIGHT/fontheight)),1); + else +#endif + { /* 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 WIKIVIEWER_PREV: /* go back */ + switch (mode) + { + case MODE_NORMAL: + if (histdepth>1) + { + advance_history(-1); + dofind=0; + goto loadnewarticle; /* ~line 1165 */ + } + + break; + + case MODE_BOOKVIEW: + remove_bookmark(bookviewoff); + bookviewoff=0; + render_bookmarks(bookviewoff); + break; + + default: + break; + } /* end mode switch */ + break; + + case WIKIVIEWER_NEXT: /* go forward */ + switch (mode) + { + case MODE_NORMAL: + if (hist[(curhist+1)].curoff>0) + { + advance_history(1); + dofind=0; + bookviewoff=0; + goto loadnewarticle; /* ~line 1165 */ + } + + break; + + case MODE_BOOKVIEW: + if (load_bookmarks(filename)) + render_bookmarks(bookviewoff); + + break; + + default: + break; + } /* end mode switch */ + break; + +#ifdef WIKIVIEWER_RECORD + case WIKIVIEWER_RECORD: /*record line*/ + case WIKIVIEWER_RECORD_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; +#endif + + 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(const void* file) +{ + PLUGINLIB_EXIT_INIT; + + rb->backlight_set_timeout(0); /*Turn off backlight timeout*/ + check_dir("/wiki"); + if (!file) + return PLUGIN_ERROR; + + rb->strlcpy(filename,file,sizeof(filename)); + 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; +} Index: apps/plugins/wikiviewer/shared/btsearch.h =================================================================== --- apps/plugins/wikiviewer/shared/btsearch.h (Revision 0) +++ apps/plugins/wikiviewer/shared/btsearch.h (Revision 0) @@ -0,0 +1,26 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef BTSEARCH_H +#define BTSEARCH_H +#include + +void search_btree(void *fp, const char* key, uint16_t rkeylen, uint32_t globoffs, + uint32_t* res_lo, uint32_t* res_hi, const bool casesense); +#endif Index: apps/plugins/wikiviewer/shared/utf8_aux.c =================================================================== --- apps/plugins/wikiviewer/shared/utf8_aux.c (Revision 0) +++ apps/plugins/wikiviewer/shared/utf8_aux.c (Revision 0) @@ -0,0 +1,117 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include "utf8_aux.h" + +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) + { + /* printf("N1:%u,N2:%u,s1p-s1:%d\n",n1,n2,s1p-s1); */ + 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) + { + /* printf("TLC\n); */ + c1=tolower(c1); + c2=tolower(c2); + } + + if(c1c2) return 1; + } + /* printf("CMPEND\n"); */ + return 0; /*won't happen*/ +} + +/* Decode 1 UTF-8 char and return a pointer to the next char. */ +const unsigned char* utf8decode(const unsigned char *utf8, unsigned short *ucs) +{ + unsigned char c = *utf8++; + unsigned long code; + int tail = 0; + + if ((c <= 0x7f) || (c >= 0xc2)) + { + /* Start of new character. */ + if (c < 0x80) /* U-00000000 - U-0000007F, 1 byte */ + code = c; + else if (c < 0xe0) /* U-00000080 - U-000007FF, 2 bytes */ + { + tail = 1; + code = c & 0x1f; + } + else if (c < 0xf0) /* U-00000800 - U-0000FFFF, 3 bytes */ + { + tail = 2; + code = c & 0x0f; + } + else if (c < 0xf5) /* U-00010000 - U-001FFFFF, 4 bytes */ + { + tail = 3; + code = c & 0x07; + } + else + /* Invalid size. */ + code = 0xfffd; + + while (tail-- && ((c = *utf8++) != 0)) + { + if ((c & 0xc0) == 0x80) + /* Valid continuation character. */ + code = (code << 6) | (c & 0x3f); + else + { + /* Invalid continuation char */ + code = 0xfffd; + utf8--; + break; + } + } + } + else + /* Invalid UTF-8 char */ + code = 0xfffd; + + /* currently we don't support chars above U-FFFF */ + *ucs = (code < 0x10000) ? code : 0xfffd; + return utf8; +} Index: apps/plugins/wikiviewer/shared/utf8_aux.h =================================================================== --- apps/plugins/wikiviewer/shared/utf8_aux.h (Revision 0) +++ apps/plugins/wikiviewer/shared/utf8_aux.h (Revision 0) @@ -0,0 +1,30 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __UTF8_AUX_H_ +#define __UTF8_AUX_H_ + +#include +#include + +const unsigned char* utf8decode(const unsigned char *utf8, unsigned short *ucs); +char utf8strcnmp(const unsigned char *s1, const unsigned char *s2, uint16_t n1, + uint16_t n2, const bool casesense); + +#endif /* __UTF8_AUX_H_ */ Index: apps/plugins/wikiviewer/shared/btsearch.c =================================================================== --- apps/plugins/wikiviewer/shared/btsearch.c (Revision 0) +++ apps/plugins/wikiviewer/shared/btsearch.c (Revision 0) @@ -0,0 +1,153 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utf8_aux.h" +#include "btsearch.h" + +#if 0 +#define DEBUGF printf +#else +#define DEBUGF(...) +#endif + +#define ROCKBOX_LITTLE_ENDIAN +#define KEY_MAXLEN 200 + +static inline unsigned short swap16(unsigned short value) +/* + result[15..8] = value[ 7..0]; + result[ 7..0] = value[15..8]; + */ +{ + return (value >> 8) | (value << 8); +} + +static inline unsigned long swap32(unsigned long value) +/* + result[31..24] = value[ 7.. 0]; + result[23..16] = value[15.. 8]; + result[15.. 8] = value[23..16]; + result[ 7.. 0] = value[31..24]; + */ +{ + unsigned long hi = swap16(value >> 16); + unsigned long lo = swap16(value & 0xffff); + return (lo << 16) | hi; +} + +#ifdef ROCKBOX_LITTLE_ENDIAN +#define letoh16(x) (x) +#define letoh32(x) (x) +#else +#define letoh16(x) swap16(x) +#define letoh32(x) swap32(x) +#endif + +#ifdef BTSEARCH_MAIN +int main(int argc,char * argv[]) +{ + if(argc<3) + printf("Usage: btsearch \n"); + else + { + FILE *fd=fopen(argv[1],"r"); + uint32_t res_lo; + uint32_t res_hi; + fseek(fd,0,SEEK_SET); + search_btree(fd, argv[2], strlen(argv[2]), 0, &res_lo, &res_hi, false); + printf("Result: %d,%d\n",res_lo,res_hi); + } + + return 0; +} + +#endif + +void search_btree(void* 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; + uint64_t dtaptr_lo,dtaptr_hi; + fread(&node_flags,sizeof(uint8_t),1,file); + fread(&node_nr_active,sizeof(uint16_t),1,file); + node_nr_active=letoh16(node_nr_active); + if(node_nr_active<1) /* error */ + goto err; + + for(i=0; i0) + fseek(file,keylen-((keylen0) + continue; + + if(utf8strcnmp(((const unsigned char*)key),((const unsigned char*)nd_key),rkeylen,keylen,casesense)==0) + { + DEBUGF("Found! %s\n", nd_key); + *res_lo=dtaptr_lo; + *res_hi=dtaptr_hi; + return; + } + + if(chldptr==0||node_flags==1) + goto err; + + fseek(file,globoffs+chldptr,SEEK_SET); + search_btree(file,key,rkeylen,globoffs,res_lo,res_hi,casesense); + return; + } + + if(node_flags!=1) /* node not leaf */ + { + fread(&chldptr,sizeof(uint32_t),1,file); + chldptr=letoh32(chldptr); + if(chldptr==0) /* leaf */ + goto err; + + fseek(file,globoffs+chldptr,SEEK_SET); + search_btree(file,key,rkeylen,globoffs,res_lo,res_hi,casesense); + } + + return; +err: + *res_lo=*res_hi=0; +} Index: apps/plugins/wikiviewer/converter/btree.c =================================================================== --- apps/plugins/wikiviewer/converter/btree.c (Revision 0) +++ apps/plugins/wikiviewer/converter/btree.c (Revision 0) @@ -0,0 +1,413 @@ +/*B-tree from lkml before 23.07.2006, licensed under GPLv2. + * btree.c Copyright (C) 2006 Vishal Patil (vishpat AT gmail DOT com) Copyright + *(C) 2006 Frederik M.J.V. (comparistion and write functions) TREE_EDITABLE + *should work, but isn't tested. + */ + +/*LE write function from rockbox, scramble.c Copyright (C) 2002 by Bjørn + Stenberg GPL*/ +#include "btree.h" + +typedef enum {left = -1,right = 1} position_t; + +typedef struct { + bt_node * node; + unsigned int index; +} node_pos; + +static void print_single_node(btree *btree, bt_node * node); +static bt_node * allocate_btree_node (unsigned int order); +static int free_btree_node (bt_node * node); + +static node_pos get_btree_node(btree * btree,void * key); + +/** + * Used to create a btree with just the root node + * @param order The order of the B-tree + * @return The an empty B-tree + */ +btree * btree_create(unsigned int order) +{ + btree * btree; + btree = mem_alloc(sizeof(*btree)); + btree->order = order; + btree->root = allocate_btree_node(order); + btree->root->leaf = true; + btree->root->nr_active = 0; + btree->root->next = NULL; + btree->root->level = 0; + return btree; +} + +/** + * Function used to allocate memory for the btree node + * @param order Order of the B-Tree + * @param leaf boolean set true for a leaf node + * @return The allocated B-tree node + */ +static bt_node * allocate_btree_node (unsigned int order) +{ + bt_node * node; + + /*Allocate memory for the node */ + node = (bt_node *)mem_alloc(sizeof(bt_node)); + + /* Initialize the number of active nodes */ + node->nr_active = 0; + + /* Initialize the keys */ + node->key_vals = (bt_key_val **)mem_alloc(2*order*sizeof(bt_key_val*) - 1); + + /* Initialize the child pointers */ + node->children = (bt_node **)mem_alloc(2*order*sizeof(bt_node*)); + + /* Use to determine whether it is a leaf */ + node->leaf = true; + + /* Use to determine the level in the tree */ + node->level = 0; + + /* Initialize the linked list pointer to NULL */ + node->next = NULL; + + return node; +} + +/** + * Function used to free the memory allocated to the b-tree + * @param node The node to be freed + * @param order Order of the B-Tree + * @return The allocated B-tree node + */ +static int free_btree_node (bt_node * node) +{ + mem_free(node->children); + mem_free(node->key_vals); + mem_free(node); + + return 0; +} + +/** + * Used to split the child node and adjust the parent so that it has two + *children + * @param parent Parent Node + * @param index Index of the child node + * @param child Full child node + * + */ +static void btree_split_child(btree * btree, bt_node * parent, + unsigned int index, + bt_node * child) +{ + unsigned int i = 0; + unsigned int order = btree->order; + + bt_node * new_child = allocate_btree_node(btree->order); + new_child->leaf = child->leaf; + new_child->level = child->level; + new_child->nr_active = btree->order - 1; + + /* Copy the higher order keys to the new child */ + for(i=0; ikey_vals[i] = child->key_vals[i + order]; + if(!child->leaf) + new_child->children[i] = + child->children[i + order]; + } + + /* Copy the last child pointer */ + if(!child->leaf) + new_child->children[i] = + child->children[i + order]; + + child->nr_active = order - 1; + + for(i = parent->nr_active + 1; i > index + 1; i--) + { + parent->children[i] = parent->children[i - 1]; + } + parent->children[index + 1] = new_child; + + for(i = parent->nr_active; i > index; i--) + { + parent->key_vals[i] = parent->key_vals[i - 1]; + } + + parent->key_vals[index] = child->key_vals[order - 1]; + parent->nr_active++; +} + +/** + * Used to insert a key in the non-full node + * @param btree The btree + * @param node The node to which the key will be added + * @param the key value pair + * @return void + */ + +static void btree_insert_nonfull (btree * btree, bt_node * parent_node, + bt_key_val * key_val) +{ + int i; + bt_node * child; + bt_node * node = parent_node; + +insert: i = node->nr_active - 1; + if(node->leaf) + { + while(i >= 0 && btree->compare(key_val->key,node->key_vals[i]->key)<0) + { + node->key_vals[i + 1] = node->key_vals[i]; + i--; + } + node->key_vals[i + 1] = key_val; + node->nr_active++; + } + else + { + while (i >= 0 && btree->compare(key_val->key,node->key_vals[i]->key)<0) + { + i--; + } + i++; + child = node->children[i]; + + if(child->nr_active == 2*btree->order - 1) + { + btree_split_child(btree,node,i,child); + if(btree->compare(key_val->key,node->key_vals[i]->key)>0) + i++; + } + + node = node->children[i]; + goto insert; + } +} + +/** + * Function used to insert node into a B-Tree + * @param root Root of the B-Tree + * @param node The node to be inserted + * @param compare Function used to compare the two nodes of the tree + * @return success or failure + */ +int btree_insert_key(btree * btree, bt_key_val * key_val) +{ + bt_node * rnode; + + rnode = btree->root; + if(rnode->nr_active == (2*btree->order - 1)) + { + bt_node * new_root; + new_root = allocate_btree_node(btree->order); + new_root->level = btree->root->level + 1; + btree->root = new_root; + new_root->leaf = false; + new_root->nr_active = 0; + new_root->children[0] = rnode; + btree_split_child(btree,new_root,0,rnode); + btree_insert_nonfull(btree,new_root,key_val); + } + else + btree_insert_nonfull(btree,rnode,key_val); + + return 0; +} + +/** + * Function used to get the node containing the given key + * @param btree The btree to be searched + * @param key The the key to be searched + * @return The node and position of the key within the node + */ +node_pos get_btree_node(btree * btree,void * key) +{ + node_pos kp; + kp.node=NULL; + kp.index=0; + bt_node * node; + unsigned int i = 0; + node = btree->root; + + for (;; i = 0) + { + /* Fix the index of the key greater than or equal to the key that we + would like to search */ + + while (i < node->nr_active && btree->compare(key, node->key_vals[i]->key)>0 ) + i++; + + /* If we find such key return the key-value pair */ + if(i < node->nr_active && btree->compare(key,node->key_vals[i]->key)==0) + { + kp.node = node; + kp.index = i; + return kp; + } + + /* If the node is leaf and if we did not find the key + return NULL */ + if(node->leaf) + return kp; + + /* To got a child node */ + node = node->children[i]; + } + return kp; +} + +/** + * Used to destory btree + * @param btree The B-tree + * @return none + */ +void btree_destroy(btree * btree) +{ + unsigned int i; + unsigned int current_level; + + bt_node * head, * tail, * node; + bt_node * child, * del_node; + + node = btree->root; + current_level = node->level; + head = node; + tail = node; + + while(true) + { + if(head == NULL) + break; + + if (head->level < current_level) + current_level = head->level; + + if(head->leaf == false) + for(i = 0; i < head->nr_active + 1; i++) + { + child = head->children[i]; + tail->next = child; + tail = child; + child->next = NULL; + } + + del_node = head; + head = head->next; + free_btree_node(del_node); + } +} + +/** + * Function used to search a node in a B-Tree + * @param btree The B-tree to be searched + * @param key Key of the node to be search + * @return The key-value pair + */ +bt_key_val * btree_search(btree * btree,void * key) +{ + bt_key_val * key_val = NULL; + node_pos kp = get_btree_node(btree,key); + + if(kp.node) + key_val = kp.node->key_vals[kp.index]; + + return key_val; +} + +#ifdef DEBUG +#include +/** + * Used to print the keys of the bt_node + * @param node The node whose keys are to be printed + * @return none + */ + +static void print_single_node(btree *btree, bt_node * node) +{ + unsigned int i = 0; + + print(" { "); + while(i < node->nr_active) + { + print("(%d)%s(%d) ",btree->key_size(node->key_vals[i]->key), + (char*)(node->key_vals[i]->key+sizeof(int16_t)),node->level); + i++; + } + print("} (0x%x,%d) ", (unsigned int)node,node->leaf); +} + +/** + * Function used to print the B-tree + * @param root Root of the B-Tree + * @param print_key Function used to print the key value + * @return none + */ + +void print_subtree(btree *btree,bt_node * node) +{ + unsigned int i; + unsigned int current_level; + + bt_node * head, * tail; + bt_node * child; + + current_level = node->level; + head = node; + tail = node; + + while(true) + { + if(head == NULL) + break; + + if (head->level < current_level) + { + current_level = head->level; + print("\n"); + } + + print_single_node(btree,head); + + if(head->leaf == false) + for(i = 0; i < head->nr_active + 1; i++) + { + child = head->children[i]; + tail->next = child; + tail = child; + child->next = NULL; + } + + head = head->next; + } + print("\n"); +} + +uint32_t btree_write(FILE *file,btree *btree,bt_node *node) +{ + long ndestrtfo,tmpfo; + unsigned short i; + ndestrtfo=ftell(file); + if(node==0) + { + printf("NDNL\n"); + return 0; + } + + uint32_t chldptrs[node->nr_active+1]; + fseek(file,ndestrtfo+btree->node_write_len(btree,node),SEEK_SET); + if(node->leaf==false) + for(i=0; i < node->nr_active+1; i++) + { + chldptrs[i]=btree_write(file,btree,node->children[i]); + } + + tmpfo=ftell(file); + fseek(file,ndestrtfo,SEEK_SET); + btree->node_write(file,btree,node,chldptrs); + fseek(file,tmpfo,SEEK_SET); + return (uint32_t)ndestrtfo; +} + +#endif Index: apps/plugins/wikiviewer/converter/sort_xmlentities.sh =================================================================== --- apps/plugins/wikiviewer/converter/sort_xmlentities.sh (Revision 0) +++ apps/plugins/wikiviewer/converter/sort_xmlentities.sh (Revision 0) @@ -0,0 +1,13 @@ +#!/bin/bash + +# Helper script which sorts xmlentities.h + +START=$(grep -m 1 -nF 'ENT("' xmlentities.h | sed 's/\([0-9]*\).*/\1/') +END=$(grep -nF 'ENT("' xmlentities.h | tail -n 1 | sed 's/\([0-9]*\).*/\1/') + +head -n $(($START - 1)) xmlentities.h > xmlentities.h.new +grep 'ENT("' xmlentities.h | LC_ALL=C sort -b | uniq >> xmlentities.h.new +awk "NR > $END { print \$0 }" xmlentities.h >> xmlentities.h.new + +rm xmlentities.h +mv xmlentities.h.new xmlentities.h Index: apps/plugins/wikiviewer/converter/btree.h =================================================================== --- apps/plugins/wikiviewer/converter/btree.h (Revision 0) +++ apps/plugins/wikiviewer/converter/btree.h (Revision 0) @@ -0,0 +1,61 @@ +/*B-tree from lkml before 23.07.2006, licensed under GPLv2. + * btree.c Copyright (C) 2006 Vishal Patil (vishpat AT gmail DOT com) Copyright + *(C) 2006 Frederik M.J.V. (comparistion and write functions) TREE_EDITABLE + *should work, but isn't tested. + */ +#ifndef _BTREE_H_ +#define _BTREE_H_ + +/* Platform dependent headers */ +#include +#include +#include +#include +#include + +#define DEBUG +#define mem_alloc malloc +#define mem_free free +#define bcopy bcopy +#define print printf + +typedef struct { + void * key; + void * val; +} bt_key_val; + +typedef struct bt_node { + struct bt_node * next; /* Pointer used for linked list */ + bool leaf; /* Used to indicate whether leaf or not */ + unsigned int nr_active; /* Number of active keys */ + unsigned int level; /* Level in the B-Tree */ + bt_key_val ** key_vals; /* Array of keys and values */ + struct bt_node ** children; /* Array of pointers to child nodes */ +} bt_node; + +typedef struct { + unsigned int order; /* B-Tree order */ + bt_node * root; /* Root of the B-Tree */ + unsigned int (*key_size)(void * key); /* Return the key size */ + unsigned int (*data_size)(void * data); /* Return the data size */ + char (*compare)(void *key1,void *key2); /* compare keys return(ret): + 1<2:ret<0 1=2:ret=0 1>2:ret>0 */ + void (*node_write)(FILE *file,void *tree,bt_node *node,uint32_t *chldptrs); + unsigned short (*node_write_len)(void *tree,bt_node *node); + void (*print_key)(void * key); /* Print the key */ +} btree; + +extern btree * btree_create(unsigned int order); +extern int btree_insert_key(btree * btree, bt_key_val * key_val); +extern int btree_delete_key(btree * btree,bt_node * subtree,void * key); +extern bt_key_val * btree_search(btree * btree, void * key); +extern void btree_destroy(btree * btree); +extern void * btree_get_max_key(btree * btree); +extern void * btree_get_min_key(btree * btree); +uint32_t btree_write(FILE *file,btree *btree,bt_node *node); +#ifdef DEBUG +extern void print_subtree(btree * btree,bt_node * node); +#endif + + +#endif Index: apps/plugins/wikiviewer/converter/xmlconv.c =================================================================== --- apps/plugins/wikiviewer/converter/xmlconv.c (Revision 0) +++ apps/plugins/wikiviewer/converter/xmlconv.c (Revision 0) @@ -0,0 +1,890 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 Matthias Larisch + * Copyright (C) 2007 Adam Gashlin (hcs) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + Usage: xmlconv wiki_xml output_prefix + + generates output_prefix.wwr, output_prefix.wwt, output_prefixN.wwa where N is + 0-? (each file ~ 1 GB) + + This is a rewrite from original ruby converter (2007 by Frederik Vestre) + */ + +#include +#include +#include +#include +#include +#include +#include "xmlconv.h" +#include "xmlentities.h" + +static FILE *titlefile; +static FILE *redirectfile; +static FILE *outfile; +static int outfilenum; +static char outfilename[PATH_MAX]; +static pcre *regex_redirect; +static int ovector_temp[30]; +static int matchcount_temp; + +static article_header buf_article_header; +static title_entry buf_title_entry; + +static void strreverse(char* begin, char* end) +{ + char aux; + while(end>begin) + { + aux=*end; + *end--=*begin; + *begin++=aux; + } +} + +static void itoa(int value, char* str, int base) +{ + static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + char* wstr=str; + int sign; + + /* Validate base */ + if (base<2 || base>35) + { + *wstr='\0'; return; + } + + /* Take care of sign */ + if ((sign=value) < 0) value = -value; + + /* Conversion. Number is reversed. */ + do { + *wstr++ = num[value%base]; + } while(value/=base); + + if(sign<0) + *wstr++='-'; + + *wstr='\0'; + + /* Reverse string */ + strreverse(str,wstr-1); +} + +static int open_outfile(int mode) +{ + char filename[PATH_MAX]; + strcpy(filename,outfilename); + if(mode==1) outfilenum++; + + itoa(outfilenum,filename+strlen(filename),10); + strcat(filename,".wwa"); + + if(mode==1) + { + if((outfile=fopen(filename,"w"))==NULL) + { + printf("Error on creating article output file\n"); + return 0; + } + } + else if((outfile=fopen(filename,"a"))==NULL) + { + printf("Error on reopening article output file\n"); + return 0; + } + + return 1; +} + +static void insert_redirect(char redirect_from[255], char redirect_to[255]) +{ + unsigned int buffer; + buffer=strlen(redirect_from); + fwrite(&buffer, sizeof(unsigned int), 1, redirectfile); + buffer=strlen(redirect_to); + fwrite(&buffer, sizeof(unsigned int), 1, redirectfile); + fputs(redirect_from,redirectfile); + fputs(redirect_to,redirectfile); +} + +/* + write a unicode value to a character buffer as UTF-8 increments *offset by + numer of bytes written to buf by hcs, based on the wikipedia article on UTF-8 + */ +static void writeUTF8(char * buf, int * offset, int value) +{ + if (value>=0 && value<=0x7f) + buf[(*offset)++]=value; + else if (value>=0x80 && value <=0x7ff) + { + buf[(*offset)++]=((value >> 6)&0x1f)|0xC0; + buf[(*offset)++]=(value&0x3f)|0x80; + } + else if (value>=0x800 && value <=0xffff) + { + buf[(*offset)++]=((value >> 12)&0xf)|0xe0; + buf[(*offset)++]=((value >> 6)&0x3f)|0x80; + buf[(*offset)++]=(value&0x3f)|0x80; + } + else if (value>=0x10000 && value <= 0x10ffff) + { + buf[(*offset)++]=((value >> 18)&0xf)|0xf0; + buf[(*offset)++]=((value >> 12)&0x3f)|0x80; + buf[(*offset)++]=((value >> 6)&0x3f)|0x80; + buf[(*offset)++]=(value&0x3f)|0x80; + } + else + perror("writeUTF8"); +} + +/* wiki code and HTML parsing (by hcs) */ + +static int inbold; +static int initalic; + +/* + int parse_(char * outbuf, const char * inbuf, int * const inlen); + outbuf: output buffer inbuf: input buffer inlength: total length of input + buffer (few parsers will consume the entire input), decremented by number of + bytes consumed + */ + +#define CONSUME(amt) { const int tempc=(amt); inbuf+=tempc; inlen-=tempc; } +#define PRODUCE(c) { (*(outbuf++))=(c); } +#define PRODUCEUTF8(c) { int temp=0; writeUTF8(outbuf, &temp, (c)); outbuf+=temp; } +/* between PARSEHEAD and PARSETAIL goes a block for the body of the while loop + */ +#define PARSEHEAD(name) static void doparse_ ## name(char ** outbufptr, const char ** inbufptr, int * const inlenptr) { \ + const char * inbuf = *inbufptr; \ + char * outbuf = *outbufptr; \ + int inlen = *inlenptr; \ + while (inlen>0) +#define PARSETAIL \ + *inbufptr = inbuf; \ + *outbufptr = outbuf; \ + *inlenptr = inlen; \ + } +#define DESCEND(name) doparse_ ## name(&outbuf,&inbuf,&inlen) +#define PASS { PRODUCE(inbuf[0]); CONSUME(1); } +#define PARSEPROTO(name) static void doparse_ ## name(char ** outbufptr, const char ** inbufptr, int * const inlenptr) +#define PARSEPROTOINLINE(name) static inline void doparse_ ## name(char ** outbufptr, const char ** inbufptr, int * const inlenptr) + +/* there has got to be a better way */ + +PARSEPROTO(comment); +PARSEPROTO(linkname); +PARSEPROTO(link); +PARSEPROTO(ref); +PARSEPROTO(article); +PARSEPROTOINLINE(text); + +/* assume we're just past the comment opening tag */ +PARSEHEAD(comment) +{ + if (inbuf[0]=='-' && !memcmp(inbuf+1,"->",5)) + { + CONSUME(6); + break; + } + else + CONSUME(1); +} +PARSETAIL + +PARSEHEAD(linkname) +{ + if (inbuf[0]=='|') + { + CONSUME(1); + /* take back anything we've written so far, only the last is display + text */ + outbuf=*outbufptr; + } + else if (inbuf[0]==']' && inbuf[1]==']') + break; + else if (inbuf[0]=='[' && inbuf[1]=='[') + { + /* for instance, links in image caption */ + PRODUCE(MARKUP_STARTLINK); + CONSUME(2); + DESCEND(link); + } + else DESCEND(text); +} +PARSETAIL + +PARSEHEAD(link) +{ + if (inbuf[0]==']' && inbuf[1]==']') + { + CONSUME(2); + PRODUCE(MARKUP_ENDLINK); + break; + } + else if (inbuf[0]=='|') + { + CONSUME(1); + PRODUCE(MARKUP_MODE); + DESCEND(linkname); + /* should come back with ]] */ + CONSUME(2); + PRODUCE(MARKUP_ENDLINK); + break; + } + else DESCEND(text); +} +PARSETAIL + +PARSEHEAD(ref) +{ + if (inbuf[0]=='&' && !memcmp(inbuf+1,"lt;/",4) && tolower(inbuf[5])=='r' && + tolower(inbuf[6])=='e' && tolower(inbuf[7])=='f' && + !memcmp(inbuf+8,">",4)) + { + CONSUME(12); + break; + } + else + CONSUME(1); +} +PARSETAIL + +PARSEHEAD(article) +{ + /* links */ + switch (inbuf[0]) + { + case '[': + if (!memcmp(inbuf,"[[",2)) + { + /* better-than-nothing image processing */ + if (!memcmp(inbuf+3,"mage:",5) && (inbuf[2]=='i' || inbuf[2]=='I')) + { + CONSUME(2); + PRODUCE(MARKUP_STARTLINK); + while (inbuf[0]!='|' && memcmp(inbuf,"]]",2) ) + { + PASS; + } + PRODUCE(MARKUP_MODE); + PRODUCE('['); + PRODUCE('I'); + PRODUCE(']'); + PRODUCE(MARKUP_ENDLINK); + PRODUCE(' '); + if (!memcmp(inbuf,"]]",2)) + { + CONSUME(2); + } + else + { + CONSUME(1); + DESCEND(linkname); + /* should come back with ]] */ + CONSUME(2); + PRODUCE('\n'); + } + } + else + { + PRODUCE(MARKUP_STARTLINK); + CONSUME(2); + DESCEND(link); + } + + break; + } + + default: + DESCEND(text); + } +} +PARSETAIL + +static int entity_comparer(const void *_key, const void *_ent) +{ + const char* key = (const char*) _key; + struct html_entity* ent = (struct html_entity*) _ent; + + return strncmp(key, ent->string, ent->string_length); +} + +/* stuff that can be anywhere in plain text */ +/* only processes current character (unless it is something we recognize) */ + +static inline void doparse_text(char ** outbufptr, const char ** inbufptr, int * const inlenptr) +{ + const char * inbuf = *inbufptr; + char * outbuf = *outbufptr; + int inlen = *inlenptr; + + switch (inbuf[0]) + { + case '\0': + printf("Read zero but end of string not reached\n"); + CONSUME(1); + break; + case '\'': + if (!memcmp(inbuf+1,"''",2)) + { + CONSUME(3); + if (inbold) + { + PRODUCE(MARKUP_ENDBOLD); + inbold=0; + } + else + { + PRODUCE(MARKUP_STARTBOLD); + inbold=1; + } + + break; + } + + if (inbuf[1]=='\'') + { + CONSUME(2); + if (initalic) + { + PRODUCE(MARKUP_ENDITALIC); + initalic=0; + } + else + { + PRODUCE(MARKUP_STARTITALIC); + initalic=1; + } + + break; + } + + PASS; + break; + case '&': + /* comment */ + if (!memcmp(inbuf+1,"lt;!--",6)) + { + CONSUME(7); + DESCEND(comment); + break; + } + + /* references (really clutter things up) */ + if (!memcmp(inbuf+1,"lt;",3) && tolower(inbuf[4])=='r' && + tolower(inbuf[5])=='e' && tolower(inbuf[6])=='f' && + (inbuf[7]=='/' || inbuf[7]==' ' || inbuf[7]=='&')) + { + int i; + CONSUME(7); + + /* handle (stanislaw lem) */ + /* find end angle bracket */ + for (i=0;; i++) + { + if (inbuf[i]=='&' && !memcmp(inbuf+i+1,"gt;",3)) + break; + } + /* check for self-terminating tag */ + if (inbuf[i-1]=='/') + { + CONSUME(i+4); + } + else + { + DESCEND(ref); + } + + break; + } + + /* entities */ + /* & > < and " are necessary for storage in XML */ + if (!memcmp(inbuf+1,"amp;",4)) + { + /* + might contain another entitized entity (– appears in the + dump as &ndash;) + */ + + CONSUME(5); + + if (inbuf[0] == '#') /* numeric (thus far untested) */ + { + int consumed=0; + int value=0; + char d; + consumed++; + if (inbuf[consumed]=='x') + { /* hexadecimal */ + for (consumed++; isxdigit(d=inbuf[consumed]); consumed++) + { + if (isupper(d)) value=value*16+d-'A'+10; + else if (islower(d)) value=value*16+d-'a'+10; + else if (isdigit(d)) value=value*16+d-'0'; + else break; /* this condition should be redundant */ + } + /* I do not consider &#x; to be a valid entity */ + if (consumed > 3 && inbuf[consumed]==';') + { +#ifdef DEBUG + { + int i; + for (i=0; i<6 && inbuf[i]!=';' && inbuf[i]!='&'; i++) ; + if (inbuf[i]==';') + { + printf("numeric entity: "); + for (i=0; inbuf[i]!=';'; i++) + { + printf("%c",inbuf[i]); + } + printf(" evaluated as 0x%x\n",value); + } + } +#endif + consumed++; + PRODUCEUTF8(value); + CONSUME(consumed); + break; + } + + /* otherwise fall through to normal handling */ + } + else /* decimal */ + { + for (; isdigit(d=inbuf[consumed]); consumed++) + { + if (isdigit(d)) value=value*10+d-'0'; + else break; /* this condition should be redundant */ + } + /* I do not consider &#; to be a valid entity */ + if (consumed > 2 && inbuf[consumed]==';') + { +#ifdef DEBUG + { + int i; + for (i=0; i<6 && inbuf[i]!=';' && inbuf[i]!='&'; i++) ; + if (inbuf[i]==';') + { + printf("numeric entity: "); + for (i=0; inbuf[i]!=';'; i++) + { + printf("%c",inbuf[i]); + } + printf(" evaluated as %d\n",value); + } + } +#endif + consumed++; + PRODUCEUTF8(value); + CONSUME(consumed); + } + + /* otherwise fall through to normal handling */ + } + } + + struct html_entity* result = bsearch(inbuf, entities, ENT_COUNT, + sizeof(struct html_entity), + &entity_comparer); + if(result != NULL) + { + PRODUCEUTF8(result->utf8); + CONSUME(result->string_length); + break; + } + + { + int i; + for (i=0; i<6 && inbuf[i]!=';' && (isalpha(inbuf[i]) || isdigit(inbuf[i])); i++) ; + if (inbuf[i]==';') + { + printf("unsupported entity: "); + for (i=0; inbuf[i]!=';'; i++) + { + printf("%c",inbuf[i]); + } + printf("\n"); + } + } + + PRODUCE('&'); + break; + } + + if (!memcmp(inbuf+1,"lt;",3)) + { + PRODUCE('<'); + CONSUME(4); + break; + } + + if (!memcmp(inbuf+1,"gt;",3)) + { + PRODUCE('>'); + CONSUME(4); + break; + } + + if (!memcmp(inbuf+1,"quot;",5)) + { + PRODUCE('"'); + CONSUME(6); + break; + } + + { + int i; + printf ("unknown entity at top level: "); + for (i=0; inbuf[i]!=';'; i++) + { + printf("%c",inbuf[i]); + } + printf("\n"); + } + + PASS; + break; + default: + PASS; + } +PARSETAIL + +static int parse_article(char * article_parsed, char * article, int article_length_temp) +{ + char * article_parsed_end = article_parsed; + const char * article_end = article; + int templen = article_length_temp; + inbold=0; + initalic=0; + doparse_article(&article_parsed_end,&article_end,&templen); + + return article_parsed_end-article_parsed; +} + +/* */ + +static void do_article(int id, char title[255], char *article, int article_length) +{ + /* Redirect processing, redirects are short in general... speedup :) */ + if(article_length<1000) + { + matchcount_temp=pcre_exec(regex_redirect, NULL, article, article_length, + 0, PCRE_NOTEMPTY, ovector_temp, 30); + if(matchcount_temp>1) + { + char redirect_to[255]; + pcre_copy_substring(article, ovector_temp, matchcount_temp, 1, + redirect_to, 255); + if(strlen(redirect_to)<1) + printf("Could not process redirect %s\n",title); + else + { + insert_redirect(title, redirect_to); + return; + } + } + } + + static char article_parsed[S_ARTBUF*2]; + int article_parsed_length=0; + + /* + This function processes the stylistics in the article. We give the + pointer as parameter so it changes our article in same memory + */ + article_parsed_length=parse_article(article_parsed, article, article_length); + + /* + At this point we should have the correct article in article-string. + This needs to be compressed using gzip and then written to the + outfile: + */ + buf_article_header.id=id; + buf_article_header.article_length=article_parsed_length; + buf_article_header.title_length=strlen(title); + if((int)ftell(outfile)+buf_article_header.article_length >= 0x40000000) + { + /* Begin new output file at about 1gb */ + fclose(outfile); + open_outfile(1); + } + + buf_title_entry.filenumber=outfilenum; + buf_title_entry.fileposition=(int)ftello(outfile); + buf_title_entry.title_length=buf_article_header.title_length; + fwrite (&buf_title_entry, sizeof(buf_title_entry), 1, titlefile); + fwrite (title, sizeof(char), buf_title_entry.title_length, titlefile); + + gzFile *gzipfile; + if((gzipfile=gzdopen(dup(fileno(outfile)),"w9"))==NULL) + { + perror("gzdopen"); + return; + } + + gzwrite(gzipfile, &buf_article_header, sizeof(buf_article_header)); + gzwrite(gzipfile, title, buf_title_entry.title_length); + gzwrite(gzipfile, article_parsed, article_parsed_length); + gzflush(gzipfile, Z_FINISH); + gzclose(gzipfile); + fseeko(outfile,0,SEEK_END); +} + +static void display_progress(long value, long max) +{ + long i, normalized_val = ((long double)value/(long double)max)*80; + + max -= 5; /* sizeof("[" "]xx%") */ + + printf("["); + for(i=0; i<80; i++) + printf("%c", i < normalized_val ? '*' : ' '); + printf("]%02d%%\r", (int) (((long double)value/(long double)max)*100)); + fflush(stdout); +} + +int main(int argc,char * argv[]) +{ + printf("Wikipedia XML Converter 0.12\n"); + if(argc < 3) + { + printf("Help:\nThis program converts wikipedia-xml-dump to rockbox ww format.\n"); + printf("Usage: xmlconv \n"); + printf("example: xmlconv dewiki.xml meindewiki\n"); + return 0; + } + + FILE *xmldump; + + strcpy(outfilename,argv[2]); + if (argv[1][0]=='-' && argv[1][1]=='\0') + { + printf("working on stdin with output prefix %s\n",argv[2]); + xmldump = stdin; + } + else + { + printf("working on %s with output prefix %s\n",argv[1], outfilename); + if((xmldump=fopen(argv[1],"rb"))==NULL) + { + printf("Error on opening input file\n"); + return 1; + } + } + + if((titlefile=fopen(strcat(outfilename,".wwt"),"wb"))==NULL) + { + printf("Error on opening title output file\n"); + return 1; + } + + strcpy(outfilename,argv[2]); + if((redirectfile=fopen(strcat(outfilename,".wwr"),"wb"))==NULL) + { + printf("Error on opening redirect output file\n"); + return 1; + } + + strcpy(outfilename,argv[2]); + outfilenum=-1; + if(!open_outfile(1)) return 1; + + long long int dumplen=0, actlen=0; + if (xmldump != stdin) + { + fseeko(xmldump,0,SEEK_END); + dumplen=ftello(xmldump); + fseeko(xmldump,0,SEEK_SET); + } + else + dumplen=-1; + + char linebuffer[S_ROWBUF]; + int i=0; + const char *error=NULL; + int erroffset; + int ovector_open[30], ovector_end[30]; + int matches_open, matches_closed; + pcre *regex_tagname, *regex_endtag, *regex_endtag_text, *regex_betweentags; + regex_tagname=pcre_compile("<([a-zA-Z0-9]+)[^>/]*(/)?>", 0, &error, &erroffset, NULL); + regex_endtag=pcre_compile("]*>", 0, &error, &erroffset, NULL); + regex_endtag_text=pcre_compile("([^<]*)]*>", 0, &error, &erroffset, NULL); + regex_betweentags=pcre_compile("<([a-zA-Z0-9]+)[^>]*>([^<]*)(]*>)?", 0, &error, &erroffset, NULL); + regex_redirect=pcre_compile("(?i)#REDIRECT:? ?\\[\\[([^\\]]*)]]", 0, &error, &erroffset, NULL); + char tagbuf_o[30]; + char tagbuf_c[30]; + char title[255]; + int id=0; + char article[S_ARTBUF+1]; + char buffer[255]; + int article_length=0; + int mode=TAG_OUTSIDE; + + i=0; + while (fgets(linebuffer,8191,xmldump)!=0) + { + i++; + if(i%5000==0 && dumplen > 0) + { + actlen=ftello(xmldump); + display_progress(actlen, dumplen); + } + + linebuffer[strlen(linebuffer)-1]=0; + matches_open=pcre_exec(regex_tagname, NULL, linebuffer, strlen(linebuffer), 0, PCRE_NOTEMPTY, ovector_open, 30); + matches_closed=pcre_exec(regex_endtag, NULL, linebuffer, strlen(linebuffer), 0, PCRE_NOTEMPTY, ovector_end, 30); + + if(matches_open>=2) + { + pcre_copy_substring(linebuffer, ovector_open, matches_open, 1, tagbuf_o, 30); + if(strcasecmp(tagbuf_o, "page")==0) + { + if(mode!=TAG_OUTSIDE) printf("page begin but not outside before\n"); + + mode=TAG_PAGE; + } + + if(strcasecmp(tagbuf_o, "title")==0 && mode==TAG_PAGE) + { + if((matches_open=pcre_exec(regex_betweentags, NULL, linebuffer, strlen(linebuffer), 0, PCRE_NOTEMPTY, ovector_open, 30))<1) + printf("title empty\n"); + else + pcre_copy_substring(linebuffer, ovector_open, matches_open, 2, title, 255); + } + + if(strcasecmp(tagbuf_o, "revision")==0) + { + if(mode!=TAG_PAGE) + printf("revision but not in page"); + + mode=TAG_REVISION; + } + + if(strcasecmp(tagbuf_o, "id")==0 && mode==TAG_REVISION) + { + if((matches_open=pcre_exec(regex_betweentags, NULL, linebuffer, + strlen(linebuffer), 0, PCRE_NOTEMPTY, ovector_open, 30))<1) + printf("id empty on %s\n", title); + else + { + pcre_copy_substring(linebuffer, ovector_open, matches_open, + 2, buffer, 255); + id=atoi(buffer); + } + } + + if(strcasecmp(tagbuf_o, "contributor")==0) + { + if(mode!=TAG_REVISION) + printf("contributor but not in revision"); + + mode=TAG_CONTRIBUTOR; + } + + if(strcasecmp(tagbuf_o, "text")==0) + { + if(mode!=TAG_REVISION) + { + printf("text but not in revision"); + if(mode!=TAG_PAGE) + printf("and even not in page"); + } + + article[0]=0; /* clear article buffer + */ + article_length=0; /* sync length */ + if(matches_open!=3) mode=TAG_TEXT; /* When there are 3 + matches -> matched + */ + else continue; /* When 3 matches -> + no text so go on */ + + if((matches_open=pcre_exec(regex_betweentags, NULL, linebuffer, + strlen(linebuffer), 0, 0, ovector_open, 30))<1) + printf("text didnt match second time\n"); + else + { + pcre_copy_substring(linebuffer, ovector_open, matches_open, + 2, article, 8191); + article_length=strlen(article); + } + } + } + else if(mode==TAG_TEXT && matches_closed<2) + { + *(article+article_length)='\n'; + strcpy(article+article_length+1,linebuffer); + article_length+=(strlen(linebuffer)+1); + if(article_length>=S_ARTBUF) + { + printf("Article buffer overflow! Bad sourcefile or increase buffersize\n"); + return 0; + } + } + + if(matches_closed==2) + { + pcre_copy_substring(linebuffer, ovector_end, matches_closed, 1, + tagbuf_c, 30); + if(strcasecmp(tagbuf_c, "contributor")==0) + { + if(mode!=TAG_CONTRIBUTOR) + printf("contributor end but not opened"); + + mode=TAG_REVISION; + } + + if(strcasecmp(tagbuf_c, "revision")==0) + { + if(mode!=TAG_REVISION) + printf("revision end but not opened"); + + mode=TAG_PAGE; + } + + if(strcasecmp(tagbuf_c, "text")==0) + { + if(mode!=TAG_TEXT) + printf("text end but not opened"); + + mode=TAG_REVISION; + do_article(id, title, article, article_length); + } + + if(strcasecmp(tagbuf_c, "page")==0) + { + if(mode!=TAG_PAGE) + printf("page end but not opened"); + + mode=TAG_OUTSIDE; + } + } + } + fclose(titlefile); + fclose(redirectfile); + fclose(outfile); + fclose(xmldump); + + return 0; +} Index: apps/plugins/wikiviewer/converter/create_ww.sh =================================================================== --- apps/plugins/wikiviewer/converter/create_ww.sh (Revision 0) +++ apps/plugins/wikiviewer/converter/create_ww.sh (Revision 0) @@ -0,0 +1,5 @@ +#!/bin/bash + +./xmlconv $1 $2 +./btcreate $2.wwt $2.wwr $2.wwi +rm $2.wwt $2.wwr Index: apps/plugins/wikiviewer/converter/btcreate.c =================================================================== --- apps/plugins/wikiviewer/converter/btcreate.c (Revision 0) +++ apps/plugins/wikiviewer/converter/btcreate.c (Revision 0) @@ -0,0 +1,259 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include "../shared/utf8_aux.h" +#include "btree.h" + +#define KEYLEN_MAX 200 +#define DEBUG 0 + +/**A key is a int_fast_16_t that holds the size in char's of the rest of the + key, and then the rest of the key*/ +static unsigned char *getkey(void* key) +{ + return (unsigned char *)(key+sizeof(uint_fast16_t)); +} + +static char compare(void *key1,void *key2) +{ +#if DEBUG == 1 + printf("CMP:%s,%s:%d:%d,%d\n", getkey(key1), getkey(key2), + utf8strcnmp(getkey(key1), getkey(key2), + *(uint_fast16_t*)key1, + *(uint_fast16_t*)key2, false), + *(uint_fast16_t*)key1, + *(uint_fast16_t*)key2); +#endif + + return utf8strcnmp(getkey(key1), getkey(key2), + *(uint_fast16_t*)key1, *(uint_fast16_t*)key2, false); +} + +static void int16le(uint16_t val, unsigned char* addr) +{ + addr[0] = val & 0xFF; + addr[1] = (val >> 8) & 0xff; +} + +static void int32le(uint32_t val, unsigned char* addr) +{ + addr[0] = val & 0xFF; + addr[1] = (val >> 8) & 0xff; + addr[2] = (val >> 16) & 0xff; + addr[3] = (val >> 24) & 0xff; +} + +static unsigned short bnode_write_len(void *tree, bt_node *node) /* depends on + key/data + structure */ +{ + (void)tree; + /*Static node length: + 1:uint8_t (flags:leaf) 2:uint16_t (nr_active) 3*/ + unsigned int i; + uint16_t bnodelen=3; + for(i=0; i < node->nr_active; i++) + { + /*Static key length: + 8:uint64_t (datapointer) 4:uint32_t (childpointer) 2:uint16_t + (keylength) 14 + */ + bnodelen += (*(uint_fast16_t*)node->key_vals[i]->key); + bnodelen += 14; + } + if(!node->leaf) + bnodelen += 4; + + return bnodelen; +} + +static void bnode_write(FILE *file,void *tree,bt_node *node,uint32_t *chldptrs) /* + depends + on + key/data + structure + */ +{ + unsigned char bnode_write_buffer[((btree*)tree)->node_write_len(tree,node)]; + memset(bnode_write_buffer,111,((btree*)tree)->node_write_len(tree,node)); + unsigned short bfcntr=0,i=0; + bnode_write_buffer[bfcntr]=node->leaf; + bfcntr++; + int16le(node->nr_active,&bnode_write_buffer[bfcntr]); + bfcntr+=2; + for(i=0; i < node->nr_active; i++) + { + /*Why do I have to write these (dataptrs) inverse of how they were + readed?*/ + int32le(((uint32_t)(*((uint32_t*)node->key_vals[i]->val))),&bnode_write_buffer[bfcntr]); + bfcntr+=4; + int32le(((uint32_t)(*((uint32_t*)(node->key_vals[i]->val+sizeof(uint32_t))))),&bnode_write_buffer[bfcntr]); + bfcntr+=4; + int32le(chldptrs[i],&bnode_write_buffer[bfcntr]); + bfcntr+=4; + int16le((*(uint_fast16_t*)node->key_vals[i]->key),&bnode_write_buffer[bfcntr]); + bfcntr+=2; + memcpy(&bnode_write_buffer[bfcntr],(node->key_vals[i]->key+sizeof(uint_fast16_t)),(*(uint_fast16_t*)node->key_vals[i]->key)); + bfcntr+=(*(uint_fast16_t*)node->key_vals[i]->key); + } + if(!node->leaf) + { + int32le(chldptrs[node->nr_active],&bnode_write_buffer[bfcntr]); + bfcntr+=4; + } + + fwrite(bnode_write_buffer,sizeof(char),bfcntr,file); /* is it correct with + sizeof */ +} + +static unsigned int keysize(void * key) +{ + return sizeof(uint_fast16_t)+(sizeof(char)*(*(uint_fast16_t*)key)); +} + +static unsigned int datasize(void * data) +{ + (void)data; + return sizeof(uint32_t)*2; +} + +static void *mallockey(unsigned char* str,uint_fast16_t length) +{ + void *ret = malloc(sizeof(uint_fast16_t)+(sizeof(unsigned char)*length)); + void *rtm=(ret+sizeof(uint_fast16_t)); + memcpy(rtm,str,length); + *((uint_fast16_t*)ret)=length; + return ret; +} + +static bt_key_val* makekv(char* key,uint_fast16_t keylen,uint32_t data1,uint32_t data2) +{ + bt_key_val * kv; + kv = (bt_key_val*)malloc(sizeof(bt_key_val)); + kv->key = mallockey((unsigned char*)key,keylen); + kv->val = malloc(sizeof(uint32_t)*2); + *(uint32_t *)kv->val = data1; + *(uint32_t *)(kv->val+sizeof(uint32_t)) = data2; + return kv; +} + +int main(int argc,char * argv[]) +{ + if(argc<4) + { + printf("Usage: \n"); + return 0; + } + + btree * tree; + bt_key_val * kv; + void *key; + bt_key_val * kvr; + tree = btree_create(30); + tree->key_size = keysize; + tree->data_size = datasize; + tree->compare = compare; + tree->node_write_len=bnode_write_len; + tree->node_write=bnode_write; + char finlne[KEYLEN_MAX+1],tinlne[KEYLEN_MAX+1]; + char elmhdr[12]; + uint_fast16_t fkeylen=0,tkeylen=0; + FILE *fd=fopen(argv[1],"r"); + while(fread(elmhdr,sizeof(uint8_t),12,fd)==12) + { + if(*((uint32_t*)&elmhdr[8])==0) + { + printf("Skipping empty\n"); + continue; + } + + fkeylen=*((uint32_t*)&elmhdr[8])0) + fseek(fd,(*((uint32_t*)&elmhdr[8]))-fkeylen,SEEK_CUR); + + finlne[fkeylen]=0; + if(strlen(finlne)!=(fkeylen)) + { + printf("Bad keylen: %s\n",finlne); + continue; + } + + kv=makekv(finlne,fkeylen,*((uint32_t*)&elmhdr),*((uint32_t*)&elmhdr[4])); + btree_insert_key(tree,kv); + kv=0; + } + printf("SCRLD\n"); + fclose(fd); + fd=NULL; + if(strlen(argv[2])!=0) + { + FILE *rfd=fopen(argv[2],"rb"); + while(fread(elmhdr,sizeof(uint8_t),8,rfd)==8) + { + if(*((uint32_t*)&elmhdr[0])==0||*((uint32_t*)&elmhdr[4])==0) + { + printf("Skipping empty\n"); + continue; + } + + fkeylen=*((uint32_t*)&elmhdr[0])0) + { + printf("MXLADJf %s,%d,skip %d\n",finlne,*(uint32_t*)&elmhdr[0],(*((uint32_t*)&elmhdr[0]))-fkeylen); + fseek(rfd,(*((uint32_t*)&elmhdr[0]))-fkeylen,SEEK_CUR); + } + + fread(tinlne,sizeof(char),tkeylen,rfd); + if((*(uint32_t*)&elmhdr[4])-tkeylen>0) + { + printf("MXLADJt %s,%d,skip %d\n",tinlne,*(uint32_t*)&elmhdr[4],(*((uint32_t*)&elmhdr[4]))-tkeylen); + fseek(rfd,(*((uint32_t*)&elmhdr[4]))-tkeylen,SEEK_CUR); + } + + finlne[fkeylen]=0; + tinlne[tkeylen]=0; + if(strlen(finlne)!=(fkeylen)||strlen(tinlne)!=(tkeylen)) + { + printf("Bad keylen: %s,%s,%d=%d,%d=%d\n",finlne,tinlne,strlen(finlne),(fkeylen),strlen(tinlne),(tkeylen)); + continue; + } + + key=mallockey((unsigned char*) tinlne,tkeylen); + if((kvr=btree_search(tree,key))!=NULL) + { + kv=makekv(finlne,fkeylen,(*((uint32_t*)kvr->val)),(*((uint32_t*)(kvr->val+sizeof(uint32_t))))); + btree_insert_key(tree,kv); + } + + free(key); + } + fclose(rfd); + rfd=NULL; + } + + FILE *ofd=fopen(argv[3],"w"); + btree_write(ofd,tree,tree->root); + fclose(ofd); + ofd=NULL; + + return 0; +} Index: apps/plugins/wikiviewer/converter/xmlentities.h =================================================================== --- apps/plugins/wikiviewer/converter/xmlentities.h (Revision 0) +++ apps/plugins/wikiviewer/converter/xmlentities.h (Revision 0) @@ -0,0 +1,289 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* adapted from http://htmlhelp.com/reference/html40/entities/ */ +/* run ./sort_xmlentities.sh when changing this file */ + +struct html_entity +{ + const char *string; + unsigned short utf8; + int string_length; +}; + +#define ENT_COUNT sizeof(entities)/sizeof(struct html_entity) +#define ENT(x, y) {x, y, sizeof(x) - 1} +struct html_entity entities[] = +{ + ENT("AElig;", 0xC6), + ENT("Aacute;", 0xC1), + ENT("Acirc;", 0xC2), + ENT("Agrave;", 0xC0), + ENT("Alpha;", 913), + ENT("Aring;", 0xC5), + ENT("Atilde;", 0xC3), + ENT("Auml;", 0xC4), + ENT("Beta;", 914), + ENT("Ccedil;", 0xC7), + ENT("Chi;", 935), + ENT("Dagger;", 8225), + ENT("Delta;", 916), + ENT("ETH;", 0xD0), + ENT("Eacute;", 0xC9), + ENT("Ecirc;", 0xCA), + ENT("Egrave;", 0xC8), + ENT("Epsilon;", 917), + ENT("Eta;", 919), + ENT("Euml;", 0xCB), + ENT("Gamma;", 915), + ENT("Iacute;", 0xCD), + ENT("Icirc;", 0xCE), + ENT("Igrave;", 0xCC), + ENT("Iota;", 921), + ENT("Iuml;", 0xCF), + ENT("Kappa;", 922), + ENT("Lambda;", 923), + ENT("Mu;", 924), + ENT("Ntilde;", 0xD1), + ENT("Nu;", 925), + ENT("OElig;", 338), + ENT("Oacute;", 0xD3), + ENT("Ocirc;", 0xD4), + ENT("Ograve;", 0xD2), + ENT("Omega;", 937), + ENT("Omicron;", 927), + ENT("Oslash;", 0xD8), + ENT("Otilde;", 0xD5), + ENT("Ouml;", 0xD6), + ENT("Phi;", 934), + ENT("Pi;", 928), + ENT("Prime;", 8243), + ENT("Psi;", 936), + ENT("Rho;", 929), + ENT("Scaron;", 352), + ENT("Sigma;", 931), + ENT("THORN;", 0xDE), + ENT("Tau;", 932), + ENT("Theta;", 920), + ENT("Uacute;", 0xDA), + ENT("Ucirc;", 0xDB), + ENT("Ugrave;", 0xD9), + ENT("Upsilon;", 933), + ENT("Uuml;", 0xDC), + ENT("Xi;", 926), + ENT("Yacute;", 0xDD), + ENT("Yuml;", 376), + ENT("Zeta;", 918), + ENT("aacute;", 0xE1), + ENT("acirc;", 0xE2), + ENT("acute;", 0xB4), + ENT("aelig;", 0xE6), + ENT("agrave;", 0xE0), + ENT("alefsym;", 8501), + ENT("alpha;", 945), + ENT("amp;", 38), + ENT("and;", 8743), + ENT("ang;", 8736), + ENT("apos;", 0x27), + ENT("aring;", 0xE5), + ENT("asymp;", 8776), + ENT("atilde;", 0xE3), + ENT("auml;", 0xE4), + ENT("bdquo;", 8222), + ENT("beta;", 946), + ENT("brvbar;", 0xA6), + ENT("bull;", 8226), + ENT("cap;", 8745), + ENT("ccedil;", 0xE7), + ENT("cedil;", 0xB8), + ENT("cent;", 0xA2), + ENT("chi;", 967), + ENT("circ;", 710), + ENT("clubs;", 9827), + ENT("cong;", 8773), + ENT("copy;", 0xA9), + ENT("crarr;", 8629), + ENT("cup;", 8746), + ENT("curren;", 0xA4), + ENT("dArr;", 8659), + ENT("dagger;", 8224), + ENT("darr;", 8595), + ENT("deg;", 0xB0), + ENT("delta;", 948), + ENT("diams;", 9830), + ENT("divide;", 0xF7), + ENT("eacute;", 0xE9), + ENT("ecirc;", 0xEA), + ENT("egrave;", 0xE8), + ENT("empty;", 8709), + ENT("emsp;", 8195), + ENT("ensp;", 8194), + ENT("epsilon;", 949), + ENT("equiv;", 8801), + ENT("eta;", 951), + ENT("eth;", 0xF0), + ENT("euml;", 0xEB), + ENT("euro;", 8364), + ENT("exist;", 8707), + ENT("fnof;", 402), + ENT("forall;", 8704), + ENT("frac12;", 0xBD), + ENT("frac13;", 0x2153), + ENT("frac14;", 0xBC), + ENT("frac34;", 0xBE), + ENT("frasl;", 8260), + ENT("gamma;", 947), + ENT("ge;", 8805), + ENT("gt;", 62), + ENT("hArr;", 8660), + ENT("harr;", 8596), + ENT("hearts;", 9829), + ENT("hellip;", 8230), + ENT("iacute;", 0xED), + ENT("icirc;", 0xEE), + ENT("iexcl;", 0xA1), + ENT("igrave;", 0xEC), + ENT("image;", 8465), + ENT("infin;", 8734), + ENT("int;", 8747), + ENT("iota;", 953), + ENT("iquest;", 0xBF), + ENT("isin;", 8712), + ENT("iuml;", 0xEF), + ENT("kappa;", 954), + ENT("lArr;", 8656), + ENT("lambda;", 955), + ENT("lang;", 9001), + ENT("laquo;", 0xAB), + ENT("larr;", 8592), + ENT("lceil;", 8968), + ENT("ldquo;", 8220), + ENT("le;", 8804), + ENT("lfloor;", 8970), + ENT("lowast;", 8727), + ENT("loz;", 9674), + ENT("lrm;", 8206), + ENT("lsaquo;", 8249), + ENT("lsquo;", 8216), + ENT("lt;", 60), + ENT("macr;", 0xAF), + ENT("mdash;", 8212), + ENT("micro;", 0xB5), + ENT("middot;", 0xB7), + ENT("minus;", 8722), + ENT("mu;", 956), + ENT("nabla;", 8711), + ENT("nbsp;", 0xA0), + ENT("ndash;", 8211), + ENT("ne;", 8800), + ENT("ni;", 8715), + ENT("not;", 0xAC), + ENT("notin;", 8713), + ENT("nsub;", 8836), + ENT("ntilde;", 0xF1), + ENT("nu;", 957), + ENT("oacute;", 0xF3), + ENT("ocirc;", 0xF4), + ENT("oelig;", 339), + ENT("ograve;", 0xF2), + ENT("oline;", 8254), + ENT("omega;", 969), + ENT("omicron;", 959), + ENT("oplus;", 8853), + ENT("or;", 8744), + ENT("ordf;", 0xAA), + ENT("ordm;", 0xBA), + ENT("oslash;", 0xF8), + ENT("otilde;", 0xF5), + ENT("otimes;", 8855), + ENT("ouml;", 0xF6), + ENT("para;", 0xB6), + ENT("part;", 8706), + ENT("permil;", 8240), + ENT("perp;", 8869), + ENT("phi;", 966), + ENT("pi;", 960), + ENT("piv;", 982), + ENT("plusmn;", 0xB1), + ENT("pm;", 0xB1), + ENT("pound;", 0xA3), + ENT("prime;", 8242), + ENT("prod;", 8719), + ENT("prop;", 8733), + ENT("psi;", 968), + ENT("quot", 34), + ENT("rArr;", 8658), + ENT("radic;", 8730), + ENT("rang;", 9002), + ENT("raquo;", 0xBB), + ENT("rarr;", 8594), + ENT("rceil;", 8969), + ENT("rdquo;", 8221), + ENT("real;", 8476), + ENT("reg;", 0xAE), + ENT("rfloor;", 8971), + ENT("rho;", 961), + ENT("rlm;", 8207), + ENT("rsaquo;", 8250), + ENT("rsquo;", 8217), + ENT("sbquo;", 8218), + ENT("scaron;", 353), + ENT("sdot;", 8901), + ENT("sect;", 0xA7), + ENT("shy;", 0xAD), + ENT("sigma;", 963), + ENT("sigmaf;", 962), + ENT("sim;", 8764), + ENT("spades;", 9824), + ENT("sub;", 8834), + ENT("sube;", 8838), + ENT("sum;", 8721), + ENT("sup1;", 0xB9), + ENT("sup2;", 0xB2), + ENT("sup3;", 0xB3), + ENT("sup;", 8835), + ENT("supe;", 8839), + ENT("szlig;", 0xDF), + ENT("tau;", 964), + ENT("there4;", 8756), + ENT("theta;", 952), + ENT("thetasym;", 977), + ENT("thinsp;", 8201), + ENT("thorn;", 0xFE), + ENT("tilde;", 732), + ENT("times;", 0xD7), + ENT("trade;", 8482), + ENT("uArr;", 8657), + ENT("uacute;", 0xFA), + ENT("uarr;", 8593), + ENT("ucirc;", 0xFB), + ENT("ugrave;", 0xF9), + ENT("uml;", 0xA8), + ENT("upsih;", 978), + ENT("upsilon;", 965), + ENT("uuml;", 0xFC), + ENT("weierp;", 8472), + ENT("xi;", 958), + ENT("yacute;", 0xFD), + ENT("yen;", 0xA5), + ENT("yuml;", 0xFF), + ENT("zeta;", 950), + ENT("zwj;", 8205), + ENT("zwnj;", 8204), +}; Index: apps/plugins/wikiviewer/converter/xmlconv.h =================================================================== --- apps/plugins/wikiviewer/converter/xmlconv.h (Revision 0) +++ apps/plugins/wikiviewer/converter/xmlconv.h (Revision 0) @@ -0,0 +1,54 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* Mode-defines: */ +#define TAG_OUTSIDE 1 +#define TAG_ERR -1 +#define TAG_PAGE 2 +#define TAG_REVISION 3 +#define TAG_TEXT 4 +#define TAG_CONTRIBUTOR 5 +#define S_ROWBUF (32*1024) /* 32kByte Rowbuffer */ +#define S_ARTBUF (8096*1024) /* 8MB Article Buffer */ +#pragma pack(push, 1) +typedef struct +{ + unsigned int id; + unsigned int article_length; + unsigned short title_length; +} article_header; + +typedef struct +{ + unsigned int filenumber; + unsigned int fileposition; + unsigned int title_length; +} title_entry; +#pragma pack(pop) + +#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 Index: apps/plugins/wikiviewer/converter/Makefile =================================================================== --- apps/plugins/wikiviewer/converter/Makefile (Revision 0) +++ apps/plugins/wikiviewer/converter/Makefile (Revision 0) @@ -0,0 +1,37 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +CC = $(PREFIX)gcc +CFLAGS=-Wall -W -g + +ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) +EXT=.exe +CFLAGS+=-mno-cygwin +else ifeq ($(findstring mingw32msvc,$(PREFIX)),mingw32msvc) +EXT=.exe +else +EXT= +endif + +all: xmlconv$(EXT) btcreate$(EXT) btsearch$(EXT) + +../shared/utf8_aux.o: ../shared/utf8_aux.h + $(CC) $(CFLAGS) -c -o $@ ../shared/utf8_aux.c + +btcreate$(EXT): btcreate.c btree.c btree.h ../shared/utf8_aux.o + $(CC) $(CFLAGS) -o $@ btcreate.c btree.c ../shared/utf8_aux.o + +btsearch$(EXT): ../shared/btsearch.c ../shared/utf8_aux.o + $(CC) $(CFLAGS) -DBTSEARCH_MAIN -o $@ ../shared/btsearch.c ../shared/utf8_aux.o + +xmlconv$(EXT): xmlconv.c xmlconv.h xmlentities.h + $(CC) $(CFLAGS) -o $@ -O3 xmlconv.c -lpcre -lz -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + +clean: + rm -f btcreate$(EXT) btsearch$(EXT) xmlconv$(EXT) utf8_aux.o Index: apps/plugins/wikiviewer/converter/README =================================================================== --- apps/plugins/wikiviewer/converter/README (Revision 0) +++ apps/plugins/wikiviewer/converter/README (Revision 0) @@ -0,0 +1,26 @@ +Wikipedia XML dump converter + +btconvert utility written by Frederik Vestre + +wikipedia-dump to media wiki viewer converter rewritten by Matthias Larisch from the +original converter written by Frederik Vestre. Great improvement in functionality by Adam Gashlin. + +help: + +make all compiles all neccessary tools + + +usage help: + +./xmlconv your_wikipedia_file output_prefix + +./btcreate output_prefix.wwt output_prefix.wwr output_prefix.wwi + +copy output_prefix.wwi and output_prefix0.wwa to your rockboxdevice + +for big wikidumps, there will be more than one .wwa file (named 0-N) + + +Bugs: + +- does not work under cygwin (segfault) Index: apps/plugins/wikiviewer/inflate.h =================================================================== --- apps/plugins/wikiviewer/inflate.h (Revision 0) +++ apps/plugins/wikiviewer/inflate.h (Revision 0) @@ -0,0 +1,27 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef INFLATE_H +#define INFLATE_H +#include +#include "plugin.h" + +uint32_t decompress(const char *inflenme,char* outbuffer,uint32_t outbuflen, + uint32_t offset,char* membuf); +#endif Index: apps/plugins/wikiviewer/bbfuncs.h =================================================================== --- apps/plugins/wikiviewer/bbfuncs.h (Revision 0) +++ apps/plugins/wikiviewer/bbfuncs.h (Revision 0) @@ -0,0 +1,31 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef BBFUNCS_H +#define BBFUNCS_H + +void error_die(const char* msg); +void error_msg(const char* msg); +size_t safe_read(int fd, void *buf, size_t count); +ssize_t full_read(int fd, void *buf, size_t len); +void xread(int fd, void *buf, ssize_t count); +unsigned char xread_char(int fd); +void check_header_gzip(int src_fd); + +#endif Index: apps/plugins/wikiviewer/mwdb.c =================================================================== --- apps/plugins/wikiviewer/mwdb.c (Revision 0) +++ apps/plugins/wikiviewer/mwdb.c (Revision 0) @@ -0,0 +1,138 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Frederik M.J. Vestre + * Copyright (C) 2006 Adam Gashlin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "mallocer.h" /*mallocer resetable memory allocator*/ +#include "inflate.h" +#include "shared/btsearch.h" +#include +#include "plugin.h" + +/*Remember to require this: + extern struct plugin_api *rb; + + Matthias Larisch: This is already done in btsearch.h. maybe it should be + moved + */ + +unsigned int mwdb_p_xtpt; + +static 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) + { +#ifdef HAVE_TOUCHSCREEN + /* this is a hack till proper touchscreen keyboard input arrives */ + rb->touchscreen_set_mode(TOUCHSCREEN_BUTTON); +#endif + if (rb->kbd_input(artnme,artnmelen)) + { + artnme[0]='\0'; +#ifdef HAVE_TOUCHSCREEN + rb->touchscreen_set_mode(TOUCHSCREEN_POINT); +#endif + return false; /* proper abort on keyboard abort */ + } +#ifdef HAVE_TOUCHSCREEN + rb->touchscreen_set_mode(TOUCHSCREEN_POINT); +#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((void*)fd,artnme,rb->strlen(artnme),0,res_lo,res_hi,casesense); + rb->close(fd); + + if(*res_hi==0) /* not found */ + return false; + else if(progress) + mwdb_nprintf("Found:%d%d",*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/wikiviewer/btsearch.c =================================================================== --- apps/plugins/wikiviewer/btsearch.c (Revision 0) +++ apps/plugins/wikiviewer/btsearch.c (Revision 0) @@ -0,0 +1,176 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" +#include "shared/btsearch.h" +#include +#define KEY_MAXLEN 512 + +static size_t sf_read(int fd, void *buf, size_t count) +{ + ssize_t n; + + do { + n = rb->read(fd, buf, count); + } while (n < 0&&n!=-1); + + return n; +} + +static 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=rb->utf8decode(s1p,&c1); + s2p=rb->utf8decode(s2p,&c2); + + if(c1==' ') c1='_'; + + if(c2==' ') c2='_'; + + if(!casesense && c1<128&&c2<128) + { + c1=tolower(c1); + c2=tolower(c2); + } + + if(c1c2) + return 1; + } + + return 0; +} + +void search_btree(void *fp,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; + int file = (int)fp; + + 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(fp,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(fp,key,rkeylen,globoffs,res_lo,res_hi,casesense); + return; + } + + *res_lo=*res_hi=0; +} Index: apps/plugins/dict2.c =================================================================== Index: apps/plugins/lib/viewer.c =================================================================== Index: apps/plugins/lib/viewer.h =================================================================== Index: apps/plugins/SUBDIRS =================================================================== --- apps/plugins/SUBDIRS (Revision 26945) +++ apps/plugins/SUBDIRS (Arbeitskopie) @@ -89,3 +89,5 @@ #if PLUGIN_BUFFER_SIZE >= 0x80000 lua #endif + +wikiviewer Index: apps/plugins/viewers.config =================================================================== --- apps/plugins/viewers.config (Revision 26945) +++ apps/plugins/viewers.config (Arbeitskopie) @@ -32,6 +32,7 @@ wav,viewers/wavplay,9 wav,viewers/wavview,10 wav,viewers/test_codec,- +wwi,viewers/wikiviewer,- bmp,viewers/test_greylib_bitmap_scale,- jpeg,viewers/test_core_jpeg,- jpe,viewers/test_core_jpeg,-