xp-framework/xp-framework — pull request #220 by ohinckel (2013-01-08 09:06:52+00:00)
Title: Fix reading files larger chunk size w/ ResourceProvider

The `lang.ResourceProvider` class is using the PHP stream wrappers to load files via "res://" scheme. This internally is using the PHP streams API which have some retriction when reading files larger than the PHP internal [CHUNK_SIZE](http://svn.php.net/viewvc/php/php-src/trunk/main/streams/php_streams_int.h?revision=321634&view=markup).

### Example
When using stream wrapper for reading files (e.g. `create(new File('/path/to/file'))->read(1024*16)`) the `read()` function will only return a buffer which is max. CHUNK_SIZE (= 8KB) bytes large. It doesn't matter which size you specify when invoking the `read()` function. It will only read max. CHUNK_SIZE bytes.

In an example application you can see this when analyzing the stracktrace when the `lang.ResourceProvider::stream_read()` function is invoked:
```
[...]
at lang.ResourceProvider::stream_read(8192) [line 0 of StackTraceElement.class.php]
at

::fread(Resource id #640, 27778) [line 374 of File.class.php]
at io.File::read(27778) [line 30 of FileUtil.class.php]
at io.FileUtil::getContents(io.File{}) [line 74 of CSVExporter.class.php]
[...]
```
In this stacktrace you can see, that we first try to use `util.FileUtil` to read the whole file, which invokes the `io.File::read()` function with the correct file size, but which will invoke the `lang.ResourceProvider::stream_read()` function with 8KB instead of the correct file size.

### Solution
The problem is in the `io.File` class which is using the PHP's `read()` functions. These function may return less then the given amount of bytes specified as argument.

According to bug [30936](https://bugs.php.net/bug.php?id=30936) the application should take care about reading the correct amount of bytes - e.g. by invoking PHP's `read()` multiple times until the requested amount of bytes are read.

This implementation changes the `io.File::read()` function to invoke `read()` as much as needed to read up the requested amount of bytes.

Maybe this patch should also be applied to the
* `io.File::gets()` - uses PHP's `fgets()` function
* `io.File::readChar()` - uses PHP's `fgetc()` function