Input streams
-------------
-For input streams, there are a few extra rules:
+For input streams, there is one extra rule:
-#) If buf is NULL, read from stream but don't store the data. This is used to skip unknown input.
#) You don't need to know the length of the message in advance. After getting EOF error when reading, set bytes_left to 0 and return false. Pb_decode will detect this and if the EOF was in a proper position, it will return true.
Here is the structure::
int fd = (intptr_t)stream->state;
int result;
- if (buf == NULL)
- {
- /* Well, this is a really inefficient way to skip input. */
- /* It is only used when there are unknown fields. */
- char dummy;
- while (count-- && recv(fd, &dummy, 1, 0) == 1);
- return count == 0;
- }
-
result = recv(fd, buf, count, MSG_WAITALL);
if (result == 0)
* pb_istream *
**************/
-bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
+static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{
- if (stream->bytes_left < count)
- PB_RETURN_ERROR(stream, "end-of-stream");
+ uint8_t *source = (uint8_t*)stream->state;
- if (!stream->callback(stream, buf, count))
- PB_RETURN_ERROR(stream, "io error");
+ if (buf != NULL)
+ memcpy(buf, source, count);
- stream->bytes_left -= count;
+ stream->state = source + count;
return true;
}
-static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
+bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{
- uint8_t *source = (uint8_t*)stream->state;
+ if (buf == NULL && stream->callback != buf_read)
+ {
+ /* Skip input bytes */
+ uint8_t tmp[16];
+ while (count > 16)
+ {
+ if (!pb_read(stream, tmp, 16))
+ return false;
+
+ count -= 16;
+ }
+
+ return pb_read(stream, tmp, count);
+ }
+
+ if (stream->bytes_left < count)
+ PB_RETURN_ERROR(stream, "end-of-stream");
- if (buf != NULL)
- memcpy(buf, source, count);
+ if (!stream->callback(stream, buf, count))
+ PB_RETURN_ERROR(stream, "io error");
- stream->state = source + count;
+ stream->bytes_left -= count;
return true;
}
* Rules for callback:
* 1) Return false on IO errors. This will cause decoding to abort.
*
- * 2) If buf is NULL, read but don't store bytes ("skip input").
- *
- * 3) You can use state to store your own data (e.g. buffer pointer),
+ * 2) You can use state to store your own data (e.g. buffer pointer),
* and rely on pb_read to verify that no-body reads past bytes_left.
*
- * 4) Your callback may be used with substreams, in which case bytes_left
+ * 3) Your callback may be used with substreams, in which case bytes_left
* is different than from the main stream. Don't use bytes_left to compute
* any pointers.
*/
[ "`./test_encode2 | ./test_decode2`" = \
"`./test_encode2 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ]
+ [ "`./test_decode2 < person_with_extra_field.pb`" = \
+ "`cat person_with_extra_field.txt`" ]
+
[ "`./test_encode_callbacks | ./test_decode_callbacks`" = \
"`./test_encode_callbacks | protoc --decode=TestMessage callbacks.proto`" ]
--- /dev/null
+name: "Test Person 99"
+id: 99
+email: "test@person.com"
FILE *file = (FILE*)stream->state;
bool status;
- if (buf == NULL)
- {
- /* Skipping data */
- while (count-- && fgetc(file) != EOF);
- return count == 0;
- }
-
status = (fread(buf, 1, count, file) == count);
if (feof(file))