Example #1
0
static enum mad_flow IoMP3Decoder_inputCallback(void *data, struct mad_stream *stream)
{
	IoMP3Decoder *self = data;
	struct mad_decoder *decoder = &(DATA(self)->decoder);
	
	IoMessage_locals_performOn_(DATA(self)->willProcessMessage, self, self);

	if (DATA(self)->isRunning)
	{
		UArray *ba = IoSeq_rawUArray(DATA(self)->inputBuffer);
		
		UArray_removeRange(ba, 0, DATA(self)->lastInputPos);
		
		{
			size_t size = UArray_size(ba);
			UArray_setSize_(ba, size + MAD_BUFFER_GUARD);
			memset(UArray_bytes(ba) + size, 0x0, MAD_BUFFER_GUARD);
			UArray_setSize_(ba, size);
		}
		
		if (UArray_size(ba) == 0) 
		{
			return MAD_FLOW_CONTINUE;
		}
		
		DATA(self)->lastInputPos = UArray_size(ba);
		
		mad_stream_buffer(stream, UArray_bytes(ba), UArray_size(ba));
	}
	
	return DATA(self)->isRunning ? MAD_FLOW_CONTINUE : MAD_FLOW_STOP;
}
Example #2
0
IO_METHOD(IoSeq, inclusiveSlice)
{
	/*doc Sequence inclusiveSlice(inclusiveStartIndex, inclusiveEndIndex)
	Returns a new string containing the subset of the
	receiver from the inclusiveStartIndex to the inclusiveEndIndex. The inclusiveEndIndex argument
	is optional. If not given, it is assumed to be the end of the string. 
	*/

	long fromIndex = IoMessage_locals_longArgAt_(m, locals, 0);
	long last = UArray_size(DATA(self));
	UArray *ba;

	if (IoMessage_argCount(m) > 1)
	{
		last = IoMessage_locals_longArgAt_(m, locals, 1);
	}

	if (last == -1)
	{
		last = UArray_size(DATA(self));
	}
	else
	{
		last = last + 1;
	}
	
	ba = UArray_slice(DATA(self), fromIndex, last);

	if (ISSYMBOL(self))
	{
		return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
	}

	return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
}
Example #3
0
IoObject *IoAsyncRequest_write(IoAsyncRequest *self, IoObject *locals, IoMessage *m)
{
	/*doc AsyncRequest write(fileOffset, aSeq, bufferOffset, numberOfBytesToWrite)
	Submits an async write request. Returns nil on error, self otherwise. 
	*/
	
	int r;
	IoSeq *data;
	UArray *ba;
	int bufferOffset;
	int bytesToWrite;

	IOCB(self)->aio_offset = (size_t)CNUMBER(IoMessage_locals_numberArgAt_(m, locals, 0));

	data = IoMessage_locals_seqArgAt_(m, locals, 1);
	ba = IoSeq_rawUArray(data);

	bufferOffset = IoMessage_locals_intArgAt_(m, locals, 2);
	bytesToWrite = IoMessage_locals_intArgAt_(m, locals, 3);

	if (bytesToWrite > UArray_size(ba) - bufferOffset)
	{
		bytesToWrite = UArray_size(ba) - bufferOffset;
	}

	IOCB(self)->aio_nbytes = bytesToWrite;
	IOCB(self)->aio_buf = realloc(IOCB_BUFFER(self), bytesToWrite);
	memcpy(IOCB_BUFFER(self), UArray_bytes(ba), bytesToWrite);

	r = aio_write(IOCB(self));

	return r == 0 ? self : IONIL(self);
}
Example #4
0
IoObject *IoDirectory_itemForDirent_(IoDirectory *self, struct dirent *dp)
{
    IoSymbol *pathString;
    int isDir;
    UArray *path = IoSeq_rawUArray(DATA(self)->path);
    UArray *ba = UArray_clone(path);

    /*
    printf("IoDirectory_itemForDirent_ path = \"%s\" %i\n", p, path->itemSize);
    printf("IoDirectory_itemForDirent_ ba = \"%s\" %i\n", UArray_asCString(ba), ba->itemSize);
    */
    if (UArray_size(ba) && !IS_PATH_SEPERATOR(UArray_longAt_(ba, UArray_size(ba) - 1)))
    {
        UArray_appendCString_(ba, IO_PATH_SEPARATOR);
    }

    UArray_appendCString_(ba, dp->d_name);
    pathString = IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);

    isDir = isDirectory(dp, CSTRING(pathString));

    if (isDir)
    {
        return IoDirectory_newWithPath_(IOSTATE, pathString);
    }

    return IoFile_newWithPath_(IOSTATE, pathString);
}
Example #5
0
IO_METHOD(IoSeq, between)
{
	/*doc Sequence between(aSequence, anotherSequence)
	Returns a new Sequence containing the bytes between the
	occurance of aSequence and anotherSequence in the receiver.
	*/

	long start = 0;
	long end = 0;
	IoSeq *fromSeq, *toSeq;

	fromSeq = (IoSeq *)IoMessage_locals_valueArgAt_(m, locals, 0);

	if (ISSEQ(fromSeq))
	{
		start = UArray_find_from_(DATA(self), DATA(fromSeq), 0) + IoSeq_rawSize(fromSeq);

		if (start == -1)
		{
			start = 0;
		}
	}
	else if (ISNIL(fromSeq))
	{
		start = 0;
	}
	else
	{
		IoState_error_(IOSTATE, m, "Nil or Sequence argument required for arg 0, not a %s",
					IoObject_name((IoObject *)fromSeq));
	}

	toSeq = (IoSeq *)IoMessage_locals_valueArgAt_(m, locals, 1);

	if (ISSEQ(toSeq))
	{
		end = UArray_find_from_(DATA(self), DATA(toSeq), start);
		if (end == -1) start = UArray_size(DATA(self));
	}
	else if (ISNIL(toSeq))
	{
		end = UArray_size(DATA(self));
	}
	else
	{
		IoState_error_(IOSTATE, m, "Nil or Sequence argument required for arg 1, not a %s",
					IoObject_name((IoObject *)toSeq));
	}

	{
		UArray *ba = UArray_slice(DATA(self), start, end);
		IoSeq *result = IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
		return result;
	}
}
Example #6
0
IO_METHOD(IoSeq, asBinarySignedInteger)
{
	/*doc Sequence asBinarySignedInteger
	Returns a Number with the bytes of the receiver interpreted as a binary signed integer. Endian is same as machine.
	*/

	const void *bytes = UArray_bytes(DATA(self));
	size_t byteCount = UArray_size(DATA(self));

	if(byteCount == 1)
	{
		return IONUMBER(*((const int8_t *)bytes));
	} 
	else if(byteCount == 2)
	{
		return IONUMBER(*((const int16_t *)bytes));
	} 
	else if(byteCount == 4)
	{
		return IONUMBER(*((const int32_t *)bytes));
	} 
	else 
	{
		IoState_error_(IOSTATE, m, "Sequence is %i bytes but only conversion of 1, 2, or 4 bytes is supported", byteCount);
	}

	return IONIL(self);
}
Example #7
0
IO_METHOD(IoSeq, asBinaryNumber)
{
	/*doc Sequence asBinaryNumber
	Returns a Number containing the first 8 bytes of the
	receiver without casting them to a double. Endian is same as machine.
	*/

	IoNumber *byteCount = IoMessage_locals_valueArgAt_(m, locals, 0);
	size_t max = UArray_size(DATA(self));
	int bc = sizeof(double);
	double d = 0;

	if (!ISNIL(byteCount))
	{
		bc = IoNumber_asInt(byteCount);
	}

	if (max < bc)
	{
		IoState_error_(IOSTATE, m, "requested first %i bytes, but Sequence only contians %i bytes", bc, max);
	}

	memcpy(&d, UArray_bytes(DATA(self)), bc);
	return IONUMBER(d);
}
Example #8
0
void Image_setData_width_height_componentCount_(Image *self, UArray *ba, int width, int height, int componentCount)
{
	int size = width * height * componentCount;

	if (size != UArray_size(ba))
	{
		printf("Image_setData_width_height_componentCount_() error - %i x %i x %i = %i, but buffer is %i\n",
			width, height, componentCount, size, (int)UArray_size(ba));
		return;
	}

	Image_copyUArray_(self, ba);
	self->width  = width;
	self->height = height;
	self->componentCount = componentCount;
}
Example #9
0
IO_METHOD(IoSeq, replaceFirstSeq)
{
	/*doc Sequence replaceFirstSeq(aSequence, anotherSequence, optionalStartIndex)
	Returns a new Sequence with the first occurance of aSequence
	replaced with anotherSequence in the receiver. If optionalStartIndex is
	provided, the search for aSequence begins at that index. Returns self.
	*/

	IoSeq *subSeq   = IoMessage_locals_seqArgAt_(m, locals, 0);
	IoSeq *otherSeq = IoMessage_locals_seqArgAt_(m, locals, 1);
	size_t startIndex = 0;

	if (IoMessage_argCount(m) > 2)
	{
		startIndex = IoMessage_locals_longArgAt_(m, locals, 2);
	}

	IO_ASSERT_NOT_SYMBOL(self);

	{
		UArray *a = DATA(self);
		UArray *b = DATA(subSeq);
		UArray *c = DATA(otherSeq);
		long i = UArray_find_from_(a, b, startIndex);
		if(i != -1)
		{
			UArray_removeRange(a, i, UArray_size(b));
			UArray_at_putAll_(a, i, c);
		}
	}
	return self;
}
Example #10
0
IO_METHOD(IoSeq, isEmpty)
{
	/*doc Sequence isEmpty
	Returns true if the size of the receiver is 0, false otherwise.
	*/

	return IOBOOL(self, UArray_size(DATA(self)) == 0);
}
Example #11
0
IoObject *IoSeq_isEmpty(IoSeq *self, IoObject *locals, IoMessage *m)
{
	/*doc Sequence isEmpty
	Returns true if the size of the receiver is 0, false otherwise.
	*/

	return IOBOOL(self, UArray_size(DATA(self)) == 0);
}
Example #12
0
static enum mad_flow IoMP3Decoder_outputCallback(void *data,
									    struct mad_header const *header,
									    struct mad_pcm *pcm)
{
	IoMP3Decoder *self = data;
	UArray *ba = IoSeq_rawUArray(DATA(self)->outputBuffer);
	unsigned int oldSize = UArray_size(ba);
	unsigned int newSize = oldSize + (pcm->length * 2 * sizeof(float));

	UArray_setSize_(ba, newSize);

	if (!DATA(self)->isRunning) 
	{
		return MAD_FLOW_STOP;
	}
	
	// MAD data is in 4 byte signed ints 
	// and on separated (not interleaved channels) 
	// so we interleave them here 
	
	{
		float *out = (float *)(UArray_bytes(ba) + oldSize);
		unsigned int nsamples  = pcm->length;
		
		mad_fixed_t const *left  = pcm->samples[0];
		mad_fixed_t const *right = pcm->samples[1];
		
		if (pcm->channels == 2)
		{
			// this would be much faster as a vector op
			while (nsamples --) 
			{
				*out = ((float)(*left)) / INT_MAX; 
				out ++; 
				*out = ((float)(*right)) / INT_MAX;
				out ++; 
				left ++;
				right ++;      
			}
		}
		else
		{
			while (nsamples --) 
			{
				float f = ((float)(*left)) / INT_MAX; 
				*out = f; 
				out ++; 
				*out = f;
				out ++; 
				left ++;
			}
		}		
	}
	
	IoMessage_locals_performOn_(DATA(self)->didProcessMessage, self, self);
	
	return DATA(self)->isRunning ? MAD_FLOW_CONTINUE : MAD_FLOW_STOP;
}
Example #13
0
uint8_t BStream_readUint8(BStream *self)
{
	if (self->index < UArray_size(self->ba))
	{
		unsigned char b = UArray_bytes(self->ba)[self->index];
		self->index ++;
		return b;
	}

	return 0;
}
Example #14
0
unsigned char *BStream_readDataOfLength_(BStream *self, size_t length)
{
	if (self->index + length <= UArray_size(self->ba))
	{
		unsigned char *b = (unsigned char *)UArray_bytes(self->ba) + self->index;
		self->index += length;
		return b;
	}

	return NULL;
}
Example #15
0
void Image_load(Image *self)
{
	if (strcmp(self->fileType, "png")==0)
	{
		PNGImage *image = PNGImage_new();
		PNGImage_setExternalUArray_(image, self->byteArray);
		PNGImage_path_(image, self->path);
		PNGImage_load(image);
		Image_error_(self, PNGImage_error(image));
		self->width  = PNGImage_width(image);
		self->height = PNGImage_height(image);
		self->componentCount = PNGImage_components(image);
		PNGImage_free(image);
	}
	else if (strcmp(self->fileType, "jpg")==0)
	{
		JPGImage *image = JPGImage_new();
		JPGImage_setExternalUArray_(image, self->byteArray);
		JPGImage_path_(image, self->path);
		JPGImage_decodingWidthHint_(image, self->decodingWidthHint);
		JPGImage_decodingHeightHint_(image, self->decodingHeightHint);
		JPGImage_load(image);
		Image_error_(self, JPGImage_error(image));
		self->width  = JPGImage_width(image);
		self->height = JPGImage_height(image);
		self->componentCount = JPGImage_components(image);
		JPGImage_free(image);
	}
	else if (strcmp(self->fileType, "tif")==0 || strcmp(self->fileType, "tiff")==0)
	{
		TIFFImage *image = TIFFImage_new();
		TIFFImage_setExternalUArray_(image, self->byteArray);
		TIFFImage_path_(image, self->path);
		TIFFImage_load(image);
		Image_error_(self, TIFFImage_error(image));
		self->width  = TIFFImage_width(image);
		self->height = TIFFImage_height(image);
		self->componentCount = TIFFImage_components(image);
		TIFFImage_free(image);
	}
	else
	{
		Image_error_(self, "unknown file type");
	}

	if (UArray_size(self->byteArray) == 0)
	{
		Image_error_(self, "error reading file");
	}

	Image_makeRGBA(self);
}
Example #16
0
IoObject *IoSeq_size(IoSeq *self, IoObject *locals, IoMessage *m)
{
/*doc Sequence size
Returns the length in number of items (which may or may not
be the number of bytes, depending on the item type) of the receiver. For example,
<p>
<pre>	
"abc" size == 3
</pre>	
*/

	return IONUMBER(UArray_size(DATA(self)));
}
Example #17
0
IO_METHOD(IoSeq, size)
{
/*doc Sequence size
Returns the length in number of items (which may or may not
be the number of bytes, depending on the item type) of the receiver. For example,
<p>
<pre>	
"abc" size == 3
</pre>	
*/

	return IONUMBER(UArray_size(DATA(self)));
}
Example #18
0
IO_METHOD(IoSeq, atInsertSeq)
{
	/*doc Sequence atInsertSeq(indexNumber, object)
	Calls asString on object and inserts the string at position indexNumber. Returns self.
	*/

	size_t n = IoMessage_locals_sizetArgAt_(m, locals, 0);
	IoSeq *otherSeq = IoMessage_locals_valueAsStringArgAt_(m, locals, 1);

	IO_ASSERT_NOT_SYMBOL(self);

	IOASSERT(n <= UArray_size(DATA(self)), "insert index out of sequence bounds");

	UArray_at_putAll_(DATA(self), n, DATA(otherSeq));

	return self;
}
Example #19
0
int AudioDevice_swapWriteBuffers(AudioDevice *self)
{
	/* clear the current buffer */
	UArray_setSize_(self->writeBuffer, 0);
	self->writeFrame = 0;

	/* swap if the next one has data */
	if (UArray_size(self->nextWriteBuffer))
	{
		void *b = self->writeBuffer;
		self->writeBuffer = self->nextWriteBuffer;
		self->nextWriteBuffer = b;
		//printf("swapping buffers self->needsData = 1\n");
		self->needsData = 1;
	}

	return 0;
}
Example #20
0
IO_METHOD(IoSeq, insertSeqEvery)
{
	/*doc MutableSequence IoSeq_insertSeqEvery(aSequence, aNumberOfItems)
	Inserts aSequence every aNumberOfItems.  Returns self.
	*/

	IoSeq *otherSeq = IoMessage_locals_valueAsStringArgAt_(m, locals, 0);
	size_t itemCount = IoMessage_locals_sizetArgAt_(m, locals, 1);

	IO_ASSERT_NOT_SYMBOL(self);

	IOASSERT(itemCount > 0, "aNumberOfItems must be > 0");
	IOASSERT(itemCount <= UArray_size(DATA(self)), "aNumberOfItems out of sequence bounds");
	
	UArray_insert_every_(DATA(self), DATA(otherSeq), itemCount);

	return self;
}
Example #21
0
void UArray_replace_with_(UArray *self, const UArray *a1, const UArray *a2)
{
    long i;
    size_t start = 0;
    UArray visible = UArray_stackRange(self, start, self->size);

    if (UArray_size(a1) == 0) return;

    while ((i = UArray_find_(&visible, a1)) != -1)
    {
        size_t index = start + i;
        UArray_removeRange(self, index, a1->size);
        UArray_at_putAll_(self, index, a2);
        start = index + a2->size;
        visible = UArray_stackRange(self, start, self->size - start);
    }
    UArray_changed(self);
}
Example #22
0
IoObject *IoZlibEncoder_process(IoZlibEncoder *self, IoObject *locals, IoMessage *m)
{
	/*doc ZlibEncoder process
	Process the inputBuffer and appends the result to the outputBuffer.
	The processed inputBuffer is empties except for the spare bytes at 
	the end which don't fit into a cipher block.
	*/
	
	z_stream *strm = DATA(self)->strm;

	UArray *input  = IoObject_rawGetMutableUArraySlot(self, locals, m, IOSYMBOL("inputBuffer"));
	UArray *output = IoObject_rawGetMutableUArraySlot(self, locals, m, IOSYMBOL("outputBuffer"));

	uint8_t *inputBytes = (uint8_t *)UArray_bytes(input);
	size_t inputSize = UArray_sizeInBytes(input);

	if (inputSize)
	{
		int ret;
		size_t oldOutputSize = UArray_size(output);
		size_t outputRoom = (inputSize * 2);
		uint8_t *outputBytes;

		UArray_setSize_(output, oldOutputSize + outputRoom);
		outputBytes = (uint8_t *)UArray_bytes(output) + oldOutputSize;

		strm->next_in   = inputBytes;
		strm->avail_in  = inputSize;

		strm->next_out  = outputBytes;
		strm->avail_out = outputRoom;

		ret = deflate(strm, Z_NO_FLUSH);
		//assert(ret != Z_STREAM_ERROR);
		{
		size_t outputSize = outputRoom - strm->avail_out;
		UArray_setSize_(output, oldOutputSize + outputSize);
		}

		UArray_setSize_(input, 0);
	}

	return self;
}
Example #23
0
UArray *UArray_asNumberArrayString(const UArray *self)
{
    UArray *out = UArray_new();
    UArray_setEncoding_(out, CENCODING_ASCII);

    UARRAY_INTFOREACH(self, i, v,
                      char s[128];

                      if(UArray_isFloatType(self))
{
    sprintf(s, "%f", (double)v);
    }
    else
    {
        sprintf(s, "%i", (int)v);
    }

    if(i != UArray_size(self) -1 ) strcat(s, ", ");
    UArray_appendBytes_size_(out, (unsigned char *)s, strlen(s));
                     );
Example #24
0
IoObject *IoLZOEncoder_process(IoLZOEncoder *self, IoObject *locals, IoMessage *m)
{
	/*doc LZOEncoder process
	Process the inputBuffer and appends the result to the outputBuffer.
	The processed inputBuffer is emptied except for the spare bytes at 
	the end which don't fit into a cipher block.
	*/
	
	lzo_align_t __LZO_MMODEL *wrkmem = DATA(self)->wrkmem;

	UArray *input  = IoObject_rawGetMutableUArraySlot(self, locals, m, IOSYMBOL("inputBuffer"));
	UArray *output = IoObject_rawGetMutableUArraySlot(self, locals, m, IOSYMBOL("outputBuffer"));

	unsigned char *inputBytes  = (uint8_t *)UArray_bytes(input);
	size_t inputSize           = UArray_sizeInBytes(input);

	if (inputSize)
	{
		int r;
		size_t oldOutputSize   = UArray_size(output);
		lzo_uint outputRoom    = (inputSize + inputSize / 64 + 16 + 3);
		unsigned char *outputBytes;

		UArray_setSize_(output, oldOutputSize + outputRoom);
		outputBytes = (uint8_t *)UArray_bytes(output) + oldOutputSize;

		r = lzo1x_1_compress(inputBytes, inputSize, outputBytes, &outputRoom, wrkmem);
		//	r = lzo1x_decompress(in, in_len, out, &out_len, wrkmem);

		if (r != LZO_E_OK)
		{
			IoState_error_(IOSTATE,  m, "LZO compression failed: %d", r);
		}


		UArray_setSize_(output, oldOutputSize + outputRoom);
		UArray_setSize_(input, 0);
	}

	return self;
}
Example #25
0
File: IoDate.c Project: bomma/io
IoDate *IoDate_fromSerialization(IoDate *self, IoObject *locals, IoMessage *m)
{
	/*doc Date fromSerialization
	Sets the date based on the serialization sequence.  Return self.
	*/
	
	IoSeq *serializationSeq = IoMessage_locals_seqArgAt_(m, locals, 0);
	UArray *serialization = UArray_clone(IoSeq_rawUArray(serializationSeq));
	
	UArray_setItemType_(serialization, CTYPE_int32_t);
	if(UArray_size(serialization) != 4)
	{
		IoState_error_(IOSTATE, self, "Expected a serialization sequence comprising 4 int32 items.");
	}
	
	Date_fromSerialization(DATA(self), serialization);
	
	UArray_free(serialization);
	
	return self;
}
Example #26
0
int AudioDevice_swapReadBuffers(AudioDevice *self)
{
	int didSwap = 0;

	if (UArray_size(self->readBuffer))
	{
		/* clear the next buffer */
		UArray_setSize_(self->nextReadBuffer, 0);
		self->readFrame = 0;

		/* swap */
		{
			void *b = self->readBuffer;
			self->readBuffer = self->nextReadBuffer;
			self->nextReadBuffer = b;
		}
		didSwap = 1;
	}

	return didSwap;
}
Example #27
0
IoObject *IoTokyoCabinetPrefixCursor_last(IoObject *self, IoObject *locals, IoMessage *m)
{
	/*doc TokyoCabinetPrefixCursor last
	Move cursor to last record. Returns self
	*/

	IoSeq *prefix = IoObject_getSlot_(self, IOSYMBOL("prefix"));
	IOASSERT(ISSEQ(prefix), "prefix must be a sequence");
	IOASSERT(TokyoCabinetPrefixCursor(self), "invalid TokyoCabinetPrefixCursor");
	
	{
		UArray *p = UArray_clone(IoSeq_rawUArray(prefix));
		UArray_appendCString_(p, " "); // space preceeds .
		
		tcbdbcurjump(TokyoCabinetPrefixCursor(self), (const void *)UArray_bytes(p), (int)UArray_size(p));
		
		UArray_free(p);
	}
	
	return IOBOOL(self, IoTokyoCabinetPrefixCursor_keyBeginsWithPrefix_(self, prefix));
}
Example #28
0
void BStream_readNumber_size_(BStream *self, unsigned char *v, int size)
{
	if (self->index + size <= UArray_size(self->ba))
	{
		const uint8_t *b = UArray_bytes(self->ba);
		memcpy(v, b + self->index, size);

		if (self->flipEndian)
		{
			reverseBytes(v, size);
		}

		self->index += size;
		return;
	}

	while (size--)
	{
		*v = 0;
		v ++;
	}
}
Example #29
0
IO_METHOD(IoSeq, at)
{
	/*doc Sequence at(aNumber)
	Returns a value at the index specified by aNumber.
	Returns nil if the index is out of bounds.
	*/

	size_t i = IoMessage_locals_sizetArgAt_(m, locals, 0);
	UArray *a = DATA(self);

	//IOASSERT((i < UArray_size(DATA(self))), "index out of bounds");
	if(i >= UArray_size(DATA(self))) return IONIL(self);

	if(UArray_isFloatType(a))
	{
		return IONUMBER(UArray_doubleAt_(a, i));
	}
	else
	{
		return IONUMBER(UArray_longAt_(a, i));
	}
}
Example #30
0
File: IoFile.c Project: achoy/io
UArray *IoFile_readUArrayOfLength_(IoFile *self, IoObject *locals, IoMessage *m)
{
	size_t length = IoMessage_locals_sizetArgAt_(m, locals, 0);
	UArray *ba = UArray_new();
	IoFile_assertOpen(self, locals, m);

	UArray_readNumberOfItems_fromCStream_(ba, length, DATA(self)->stream);

	if (ferror(DATA(self)->stream) != 0)
	{
		clearerr(DATA(self)->stream);
		UArray_free(ba);
		IoState_error_(IOSTATE, m, "error reading file '%s'", UTF8CSTRING(DATA(self)->path));
	}

	if (!UArray_size(ba))
	{
		UArray_free(ba);
		return NULL;
	}

	return ba;
}