protected String readString(InputStream in) throws IOException {
		
		int length = readInt(in);

		// Avoid allocating a rediculous array size.
		// But InputStreams don't universally track position/size.
		// And available() might only mean blocking, not the end.
		// So try some special cases...
		if ( in instanceof FileInputStream ) {
			FileInputStream fin = (FileInputStream)in;
			long position = fin.getChannel().position();
			if ( length > fin.getChannel().size() - position)
				throw new RuntimeException( "Expected string length ("+ length +") would extend beyond the end of the stream, from current position ("+ position +")" );
		}
		else {
			// Call available on streams that really end.
			int remaining = -1;
			if ( in instanceof MappedDatParser.ByteBufferBackedInputStream ) {
				remaining = ((MappedDatParser.ByteBufferBackedInputStream)in).available();
			}
			else if ( in instanceof ByteArrayInputStream ) {
				remaining = ((ByteArrayInputStream)in).available();
			}
			if (remaining != -1 && length > remaining )
				throw new RuntimeException( "Expected string length ("+ length +") would extend beyond the end of the stream" );
		}
		
		int numRead = 0;
		int offset = 0;
		byte[] strarr = new byte[length];
		while (offset < strarr.length && (numRead = in.read(strarr, offset, strarr.length)) >= 0)
			offset += numRead;

		if ( offset < strarr.length )
			throw new RuntimeException( "End of stream reached before reading enough bytes for string of length "+ length );
		
		return new String(strarr);
		
	}