#include "winhelp.h"
#include "tree234.h"
-#ifdef TESTMODE
+#ifdef WINHELP_TESTMODE
/*
* This lot is useful for testing. Something like it will also be
* needed to use this module standalone.
#define smalloc malloc
#define srealloc realloc
#define sfree free
-#define mknew(type) ( (type *) smalloc (sizeof (type)) )
-#define mknewa(type, number) ( (type *) smalloc ((number) * sizeof (type)) )
-#define resize(array, len) ( srealloc ((array), (len) * sizeof (*(array))) )
+#define snew(type) ( (type *) smalloc (sizeof (type)) )
+#define snewn(number, type) ( (type *) smalloc ((number) * sizeof (type)) )
+#define sresize(array, len, type) \
+ ( (type *) srealloc ((array), (len) * sizeof (type)) )
#define lenof(array) ( sizeof(array) / sizeof(*(array)) )
char *dupstr(char *s) {
- char *r = mknewa(char, 1+strlen(s)); strcpy(r,s); return r;
+ char *r = snewn(1+strlen(s), char); strcpy(r,s); return r;
}
#endif
int para_flags;
int para_attrs[7];
int ncontexts;
+ int picture_index;
};
/* Functions to return the index and leaf data for B-tree contents. */
static void whlp_file_add_char(struct file *f, int data);
static void whlp_file_add_short(struct file *f, int data);
static void whlp_file_add_long(struct file *f, int data);
+static void whlp_file_add_cushort(struct file *f, int data);
+static void whlp_file_add_csshort(struct file *f, int data);
+static void whlp_file_add_culong(struct file *f, int data);
+static void whlp_file_add_cslong(struct file *f, int data);
static void whlp_file_fill(struct file *f, int len);
static void whlp_file_seek(struct file *f, int pos, int whence);
static int whlp_file_offset(struct file *f);
"\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF";
unsigned long hash;
- /* Sanity check the size of unsigned long */
- enum { assertion = 1 /
- (((unsigned long)0xFFFFFFFF) + 2 == (unsigned long)1) };
-
/*
* The hash algorithm starts the hash at 0 and updates it with
* each character. Therefore, logically, the hash of an empty
*/
hash = 0;
while (*context) {
- hash = hash * 43 + bytemapping[(unsigned char)*context];
+ /*
+ * Be careful of overflowing `unsigned long', for maximum
+ * portability.
+ */
+
+ /*
+ * Multiply `hash' by 43.
+ */
+ {
+ unsigned long bottom, top;
+ bottom = (hash & 0xFFFFUL) * 43;
+ top = ((hash >> 16) & 0xFFFFUL) * 43;
+ top += (bottom >> 16);
+ bottom &= 0xFFFFUL;
+ top &= 0xFFFFUL;
+ hash = (top << 16) | bottom;
+ }
+
+ /*
+ * Add the mapping value for this byte to `hash'.
+ */
+ {
+ int val = bytemapping[(unsigned char)*context];
+
+ if (val > 0 && hash > (0xFFFFFFFFUL - val)) {
+ hash -= (0xFFFFFFFFUL - val) + 1;
+ } else if (val < 0 && hash < (unsigned long)-val) {
+ hash += (0xFFFFFFFFUL + val) + 1;
+ } else
+ hash += val;
+ }
+
context++;
}
return hash;
WHLP_TOPIC whlp_register_topic(WHLP h, char *context_name, char **clash)
{
- context *ctx = mknew(context);
+ context *ctx = snew(context);
context *otherctx;
/*
while ( (ctx = index234(h->pre_contexts, 0)) != NULL ) {
delpos234(h->pre_contexts, 0);
- ctx->name = mknewa(char, 20);
+ ctx->name = snewn(20, char);
do {
sprintf(ctx->name, "t%08d", ctx_num++);
ctx->hash = context_hash(ctx->name);
void whlp_begin_topic(WHLP h, WHLP_TOPIC topic, char *title, ...)
{
- struct topiclink *link = mknew(struct topiclink);
+ struct topiclink *link = snew(struct topiclink);
int len, slen;
char *macro;
va_list ap;
link->recordtype = 2; /* topic header */
link->len1 = 4*7; /* standard linkdata1 size */
- link->data1 = mknewa(unsigned char, link->len1);
+ link->data1 = snewn(link->len1, unsigned char);
slen = strlen(title);
assert(slen+1 <= TOPIC_BLKSIZE);
len--; /* lose the last \0 on the last macro */
link->len2 = len;
- link->data2 = mknewa(unsigned char, link->len2);
+ link->data2 = snewn(link->len2, unsigned char);
memcpy(link->data2, h->linkdata2, link->len2);
topic->title = dupstr(title);
static void whlp_linkdata(WHLP h, int which, int c)
{
int *len = (which == 1 ? &h->link->len1 : &h->link->len2);
- char *data = (which == 1 ? h->linkdata1 : h->linkdata2);
+ unsigned char *data = (which == 1 ? h->linkdata1 : h->linkdata2);
assert(*len < TOPIC_BLKSIZE);
data[(*len)++] = c;
}
if (alignment == WHLP_ALIGN_RIGHT)
tabstop |= 0x10000;
- p = mknew(int);
+ p = snew(int);
*p = tabstop;
add234(h->tabstops, p);
h->para_flags |= 0x0200;
void whlp_begin_para(WHLP h, int para_type)
{
- struct topiclink *link = mknew(struct topiclink);
+ struct topiclink *link = snew(struct topiclink);
int i;
/*
whlp_linkdata(h, 1, 0x83);
}
+int whlp_add_picture(WHLP h, int wd, int ht, const void *vpicdata,
+ const unsigned long *palette)
+{
+ struct file *f;
+ char filename[80];
+ const unsigned char *picdata = (const unsigned char *)vpicdata;
+ int picstart, picoff, imgoff, imgstart;
+ int palettelen;
+ int i, index;
+ int wdrounded;
+
+ /*
+ * Determine the limit of the colour palette.
+ */
+ palettelen = -1;
+ for (i = 0; i < wd*ht; i++)
+ if (palettelen < picdata[i])
+ palettelen = picdata[i];
+ palettelen++;
+
+ /*
+ * Round up the width to the next multiple of 4.
+ */
+ wdrounded = (wd + 3) & ~3;
+
+ index = h->picture_index++;
+ sprintf(filename, "bm%d", index);
+
+ f = whlp_new_file(h, filename);
+ whlp_file_add_short(f, 0x706C); /* magic number */
+ whlp_file_add_short(f, 1); /* number of pictures */
+ picoff = whlp_file_offset(f);
+ whlp_file_add_long(f, 0); /* offset of first (only) picture */
+ picstart = whlp_file_offset(f);
+ whlp_file_add_char(f, 6); /* DIB */
+ whlp_file_add_char(f, 0); /* no packing */
+ whlp_file_add_culong(f, 100); /* xdpi */
+ whlp_file_add_culong(f, 100); /* ydpi */
+ whlp_file_add_cushort(f, 1); /* planes (?) */
+ whlp_file_add_cushort(f, 8); /* bitcount */
+ whlp_file_add_culong(f, wd); /* width */
+ whlp_file_add_culong(f, ht); /* height */
+ whlp_file_add_culong(f, palettelen);/* colours used */
+ whlp_file_add_culong(f, palettelen);/* colours important */
+ whlp_file_add_culong(f, wdrounded*ht); /* `compressed' data size */
+ whlp_file_add_culong(f, 0); /* hotspot size (no hotspots) */
+ imgoff = whlp_file_offset(f);
+ whlp_file_add_long(f, 0); /* offset of `compressed' data */
+ whlp_file_add_long(f, 0); /* offset of hotspot data (none) */
+ for (i = 0; i < palettelen; i++)
+ whlp_file_add_long(f, palette[i]);
+ imgstart = whlp_file_offset(f);
+ /*
+ * Windows Help files, like BMP, start from the bottom scanline.
+ */
+ for (i = ht; i-- > 0 ;) {
+ whlp_file_add(f, picdata + i*wd, wd);
+ if (wd < wdrounded)
+ whlp_file_add(f, "\0\0\0", wdrounded - wd);
+ }
+
+ /* Now go back and fix up internal offsets */
+ whlp_file_seek(f, picoff, 0);
+ whlp_file_add_long(f, picstart);
+ whlp_file_seek(f, imgoff, 0);
+ whlp_file_add_long(f, imgstart - picstart);
+ whlp_file_seek(f, 0, 2);
+
+ return index;
+}
+
+void whlp_ref_picture(WHLP h, int picid)
+{
+ /*
+ * Write a NUL into linkdata2.
+ */
+ whlp_linkdata(h, 2, 0);
+ /*
+ * Write the formatting command and its followup data to
+ * specify a picture in a separate file.
+ */
+ whlp_linkdata(h, 1, 0x86);
+ whlp_linkdata(h, 1, 3); /* type (picture without hotspots) */
+ whlp_linkdata_cslong(h, 1, 4);
+ whlp_linkdata_short(h, 1, 0);
+ whlp_linkdata_short(h, 1, picid);
+}
+
void whlp_text(WHLP h, char *text)
{
while (*text) {
whlp_linkdata_cslong(h, 1, data1cut);
whlp_linkdata_cushort(h, 1, h->link->len2);
- h->link->data1 = mknewa(unsigned char, h->link->len1);
+ h->link->data1 = snewn(h->link->len1, unsigned char);
memcpy(h->link->data1, h->linkdata1 + data1cut, h->link->len1 - data1cut);
memcpy(h->link->data1 + h->link->len1 - data1cut, h->linkdata1, data1cut);
- h->link->data2 = mknewa(unsigned char, h->link->len2);
+ h->link->data2 = snewn(h->link->len2, unsigned char);
memcpy(h->link->data2, h->linkdata2, h->link->len2);
addpos234(h->text, h->link, count234(h->text));
/*
* Create a final TOPICLINK containing no usable data.
*/
- link = mknew(struct topiclink);
+ link = snew(struct topiclink);
link->nexttopic = NULL;
if (h->prevtopic)
h->prevtopic->nexttopic = link;
h->prevtopic = link;
- link->data1 = mknewa(unsigned char, 0x1c);
+ link->data1 = snewn(0x1c, unsigned char);
link->block_size = 0;
link->data2 = NULL;
link->len1 = 0x1c;
void whlp_index_term(WHLP h, char *index, WHLP_TOPIC topic)
{
- struct indexrec *idx = mknew(struct indexrec);
+ struct indexrec *idx = snew(struct indexrec);
idx->term = dupstr(index);
idx->topic = topic;
sfree(fontname);
}
- fontdesc = mknew(struct fontdesc);
+ fontdesc = snew(struct fontdesc);
fontdesc->font = font;
fontdesc->family = family;
fontdesc->halfpoints = halfpoints;
int npages = 0, pagessize = 0;
int npages_this_level, nentries, nlevels;
int total_leaf_entries;
- char btdata[MAX_PAGE_SIZE];
+ unsigned char btdata[MAX_PAGE_SIZE];
int btlen;
int page_start, fixups_offset, unused_bytes;
void *element;
npages_this_level++;
if (npages >= pagessize) {
pagessize = npages + 32;
- page_elements = resize(page_elements, pagessize);
+ page_elements = sresize(page_elements, pagessize, void *);
}
page_elements[npages++] = element;
npages_this_level++;
if (npages >= pagessize) {
pagessize = npages + 32;
- page_elements = resize(page_elements, pagessize);
+ page_elements = sresize(page_elements, pagessize, void *);
}
page_elements[npages++] = page_elements[current];
static struct file *whlp_new_file(WHLP h, char *name)
{
struct file *f;
- f = mknew(struct file);
+ f = snew(struct file);
f->data = NULL;
f->pos = f->len = f->size = 0;
if (name) {
{
if (f->pos + len > f->size) {
f->size = f->pos + len + 1024;
- f->data = resize(f->data, f->size);
+ f->data = sresize(f->data, f->size, unsigned char);
}
memcpy(f->data + f->pos, data, len);
f->pos += len;
whlp_file_add(f, s, 4);
}
+static void whlp_file_add_cushort(struct file *f, int data)
+{
+ if (data <= 0x7F) {
+ whlp_file_add_char(f, data*2);
+ } else {
+ whlp_file_add_char(f, 1 + (data%128 * 2));
+ whlp_file_add_char(f, data/128);
+ }
+}
+
+#if 0 /* currently unused */
+static void whlp_file_add_csshort(struct file *f, int data)
+{
+ if (data >= -0x40 && data <= 0x3F)
+ whlp_file_add_cushort(f, data+64);
+ else
+ whlp_file_add_cushort(f, data+16384);
+}
+#endif
+
+static void whlp_file_add_culong(struct file *f, int data)
+{
+ if (data <= 0x7FFF) {
+ whlp_file_add_short(f, data*2);
+ } else {
+ whlp_file_add_short(f, 1 + (data%32768 * 2));
+ whlp_file_add_short(f, data/32768);
+ }
+}
+
+#if 0 /* currently unused */
+static void whlp_file_add_cslong(struct file *f, int data)
+{
+ if (data >= -0x4000 && data <= 0x3FFF)
+ whlp_file_add_culong(f, data+16384);
+ else
+ whlp_file_add_culong(f, data+67108864);
+}
+#endif
+
static void whlp_file_fill(struct file *f, int len)
{
if (f->pos + len > f->size) {
f->size = f->pos + len + 1024;
- f->data = resize(f->data, f->size);
+ f->data = sresize(f->data, f->size, unsigned char);
}
memset(f->data + f->pos, 0, len);
f->pos += len;
WHLP ret;
struct file *f;
- ret = mknew(struct WHLP_tag);
+ ret = snew(struct WHLP_tag);
/*
* Internal B-trees.
ret->prevtopic = NULL;
ret->ncontexts = 0;
ret->link = NULL;
+ ret->picture_index = 0;
return ret;
}
sfree(h);
}
-#ifdef TESTMODE
+#ifdef WINHELP_TESTMODE
+
+#ifdef PICTURE_FROM_CMDLINE
+#include "png.h"
+#include "colquant.h"
+#include "dither.h"
+#endif
-int main(void)
+int main(int argc, char **argv)
{
WHLP h;
WHLP_TOPIC t1, t2, t3;
whlp_begin_para(h, WHLP_PARA_SCROLL);
whlp_set_font(h, 1);
- whlp_text(h, "This third topic is almost as boring as the first. Woo!");
+ whlp_text(h, "This third topic is not nearly as boring as the first, "
+ "because it has a picture: ");
+ {
+#ifndef PICTURE_FROM_CMDLINE
+ const unsigned long palette[] = {
+ 0xFF0000,
+ 0xFFFF00,
+ 0x00FF00,
+ 0x00FFFF,
+ 0x0000FF,
+ };
+ const unsigned char picture[] = {
+ 0, 0, 0, 0, 1, 2, 3, 4,
+ 0, 0, 0, 0, 1, 2, 3, 4,
+ 0, 0, 0, 0, 1, 2, 3, 4,
+ 0, 0, 0, 1, 2, 3, 4, 4,
+ 0, 0, 0, 1, 2, 3, 4, 4,
+ 0, 0, 0, 1, 2, 3, 4, 4,
+ 0, 0, 1, 2, 3, 4, 4, 4,
+ 0, 0, 1, 2, 3, 4, 4, 4,
+ 0, 0, 1, 2, 3, 4, 4, 4,
+ 0, 1, 2, 3, 4, 4, 4, 4,
+ 0, 1, 2, 3, 4, 4, 4, 4,
+ 0, 1, 2, 3, 4, 4, 4, 4,
+ };
+ int wid = 8, ht = 12;
+#else
+ png_pixel ppalette[256];
+ unsigned long palette[256];
+ unsigned char *picture;
+ png *png;
+ colquant *cq;
+ int plen, i, err, wid, ht;
+
+ if (argc < 2) {
+ fprintf(stderr, "in this mode I need a .png file on the"
+ " command line\n");
+ return 1;
+ }
+ png = png_decode_file(argv[1], &err);
+ if (!png) {
+ fprintf(stderr, "%s: PNG read error: %s\n", argv[1],
+ png_error_msg[err]);
+ return 1;
+ }
+
+ cq = colquant_new(256, 8);
+ colquant_data(cq, png->pixels, png->width * png->height);
+ plen = colquant_get_palette(cq, ppalette);
+ colquant_free(cq);
+ assert(plen <= 256);
+ for (i = 0; i < plen; i++) {
+ palette[i] = ppalette[i].r >> 8;
+ palette[i] <<= 8;
+ palette[i] |= ppalette[i].g >> 8;
+ palette[i] <<= 8;
+ palette[i] |= ppalette[i].b >> 8;
+ }
+ picture = malloc(png->width * png->height);
+ dither_image(png->width, png->height, png->pixels,
+ ppalette, plen, picture);
+ wid = png->width;
+ ht = png->height;
+ png_free(png);
+
+#endif
+ whlp_ref_picture(h, whlp_add_picture(h, wid, ht, picture, palette));
+ }
whlp_end_para(h);
/*