File:  [RetroPC.NET] / np2 / common / textfile.c
Revision 1.6: download - view: text, annotated - select for diffs
Sun Mar 20 03:54:58 2005 JST (20 years, 7 months ago) by yui
Branches: MAIN
CVS tags: HEAD
fix text file reader (T.Yui)

#include	"compiler.h"
#include	"dosio.h"
#include	"textfile.h"


typedef struct {
	UINT	mode;
	FILEH	fh;
	BOOL	xendian;
} _TEXTFH, *TEXTFH;

typedef struct {
	_TEXTFH	tf;
	UINT8	*buf;
	UINT	bufsize;
	UINT	bufpos;
	UINT	bufrem;
} _TEXTREAD, *TEXTREAD;


// ---- A

static UINT fillbufferA(TEXTREAD tr) {

	UINT	rsize;

	if (tr->bufrem == 0) {
		rsize = file_read(tr->tf.fh, tr->buf, tr->bufsize);
		tr->bufpos = 0;
		tr->bufrem = rsize;
	}
	return(tr->bufrem);
}

static BRESULT readlineA(TEXTREAD tr, void *buffer, UINT size) {

	UINT8	*dst;
	BOOL	crlf;
	BRESULT	ret;
	UINT8	c;
const UINT8	*src;
	UINT	pos;

	if (size == 0) {
		dst = NULL;
		size = 0;
	}
	else {
		dst = (UINT8 *)buffer;
		size--;
	}

	crlf = FALSE;
	ret = FAILURE;
	c = 0;
	do {
		if (fillbufferA(tr) == 0) {
			break;
		}
		ret = SUCCESS;
		src = tr->buf;
		src += tr->bufpos;
		pos = 0;
		while(pos<tr->bufrem) {
			c = src[pos];
			pos++;
			if ((c == 0x0d) || (c == 0x0a)) {
				crlf = TRUE;
				break;
			}
			if (size) {
				size--;
				*dst++ = c;
			}
		}
		tr->bufpos += pos;
		tr->bufrem -= pos;
	} while(!crlf);
	if ((crlf) && (c == 0x0d)) {
		if (fillbufferA(tr) != 0) {
			src = tr->buf;
			src += tr->bufpos;
			if (*src == 0x0a) {
				tr->bufpos++;
				tr->bufrem--;
			}
		}
	}
	if (dst) {
		*dst = '\0';
	}
	return(ret);
}


// ---- W

static UINT fillbufferW(TEXTREAD tr) {

	UINT	rsize;
	UINT8	*buf;
	UINT8	tmp;

	if (tr->bufrem == 0) {
		buf = tr->buf;
		rsize = file_read(tr->tf.fh, buf, tr->bufsize) / 2;
		tr->bufpos = 0;
		tr->bufrem = rsize / 2;
		if (tr->tf.xendian) {
			while(rsize) {
				tmp = buf[0];
				buf[0] = buf[1];
				buf[1] = tmp;
				buf += 2;
				rsize--;
			}
		}
	}
	return(tr->bufrem);
}

static BRESULT readlineW(TEXTREAD tr, void *buffer, UINT size) {

	UINT16		*dst;
	BOOL		crlf;
	BRESULT		ret;
	UINT16		c;
const UINT16	*src;
	UINT		pos;

	if (size == 0) {
		dst = NULL;
		size = 0;
	}
	else {
		dst = (UINT16 *)buffer;
		size--;
	}
	crlf = FALSE;
	ret = FAILURE;
	c = 0;
	do {
		if (fillbufferW(tr) == 0) {
			break;
		}
		ret = SUCCESS;
		src = (UINT16 *)tr->buf;
		src += tr->bufpos;
		pos = 0;
		while(pos<tr->bufrem) {
			c = src[pos];
			pos++;
			if ((c == 0x0d) || (c == 0x0a)) {
				crlf = TRUE;
				break;
			}
			if (size) {
				size--;
				*dst++ = c;
			}
		}
		tr->bufpos += pos;
		tr->bufrem -= pos;
	} while(!crlf);
	if ((crlf) && (c == 0x0d)) {
		if (fillbufferW(tr) != 0) {
			src = (UINT16 *)tr->buf;
			src += tr->bufpos;
			if (*src == 0x0a) {
				tr->bufpos++;
				tr->bufrem--;
			}
		}
	}
	if (dst) {
		*dst = '\0';
	}
	return(ret);
}


// ----

TEXTFILEH textfile_open(const OEMCHAR *filename, UINT buffersize) {

	FILEH		fh;
	UINT8		hdr[4];
	UINT		hdrsize;
	long		fpos;
	UINT		srcwidth;
	BOOL		xendian;
	TEXTREAD	ret;

	buffersize = buffersize & (~3);
	if (buffersize < 256) {
		buffersize = 256;
	}
	fh = file_open_rb(filename);
	if (fh == FILEH_INVALID) {
		goto tfo_err1;
	}
	hdrsize = file_read(fh, hdr, 4);
	fpos = 0;
	srcwidth = 1;
	xendian = FALSE;
	if ((hdrsize >= 3) &&
		(hdr[0] == 0xef) && (hdr[1] == 0xbb) && (hdr[2] == 0xbf)) {
		// UTF-8
		fpos = 3;
	}
	else if ((hdrsize >= 2) && (hdr[0] == 0xff) && (hdr[1] == 0xfe)) {
		// UCSLE
		fpos = 2;
		srcwidth = 2;
#if defined(BYTESEX_BIG)
		xendian = TRUE;
#endif
	}
	else if ((hdrsize >= 2) && (hdr[0] == 0xfe) && (hdr[1] == 0xff)) {
		// UCS2BE
		fpos = 2;
		srcwidth = 2;
#if defined(BYTESEX_LITTLE)
		xendian = TRUE;
#endif
	}

	if (srcwidth != sizeof(OEMCHAR)) {
		goto tfo_err2;
	}
	buffersize = buffersize * sizeof(OEMCHAR);

	if (file_seek(fh, fpos, FSEEK_SET) != fpos) {
		goto tfo_err2;
	}

	ret = (TEXTREAD)_MALLOC(sizeof(_TEXTREAD) + buffersize, filename);
	if (ret == NULL) {
		goto tfo_err2;
	}
	ZeroMemory(ret, sizeof(_TEXTREAD));
	ret->tf.mode = 0;
	ret->tf.fh = fh;
	ret->tf.xendian = xendian;
	ret->buf = (UINT8 *)(ret + 1);
	ret->bufsize = buffersize;
	return((TEXTFILEH)ret);

tfo_err2:
	file_close(fh);

tfo_err1:
	return(NULL);
}

void textfile_close(TEXTFILEH tfh) {

	if (tfh) {
		file_close(((TEXTFH)tfh)->fh);
		_MFREE(tfh);
	}
}

BRESULT textfile_read(TEXTFILEH tfh, OEMCHAR *buffer, UINT size) {

	TEXTREAD	tr;

	tr = (TEXTREAD)tfh;
	if (tr) {
		if (sizeof(OEMCHAR) == 1) {
			return(readlineA(tr, buffer, size));
		}
		else if (sizeof(OEMCHAR) == 2) {
			return(readlineW(tr, buffer, size));
		}
	}
	return(FAILURE);
}


RetroPC.NET-CVS <cvs@retropc.net>