+
+ if (perform_flush) {
+ size_t flush_max;
+ if (cx_szmul(buffer->flush_blkmax, buffer->flush_blksize, &flush_max)) {
+ return 0;
+ }
+ size_t flush_pos = buffer->flush_func == NULL || buffer->flush_target == NULL
+ ? buffer->pos
+ : cx_buffer_write_flush_helper(buffer, buffer->bytes, 1, buffer->pos);
+ if (flush_pos == buffer->pos) {
+ // entire buffer has been flushed, we can reset
+ buffer->size = buffer->pos = 0;
+
+ size_t items_flush; // how many items can also be directly flushed
+ size_t items_keep; // how many items have to be written to the buffer
+
+ items_flush = flush_max >= required ? nitems : (flush_max - flush_pos) / size;
+ if (items_flush > 0) {
+ items_flush = cx_buffer_write_flush_helper(buffer, ptr, size, items_flush / size);
+ // in case we could not flush everything, keep the rest
+ }
+ items_keep = nitems - items_flush;
+ if (items_keep > 0) {
+ // try again with the remaining stuff
+ unsigned char const *new_ptr = ptr;
+ new_ptr += items_flush * size;
+ // report the directly flushed items as written plus the remaining stuff
+ return items_flush + cxBufferWrite(new_ptr, size, items_keep, buffer);
+ } else {
+ // all items have been flushed - report them as written
+ return nitems;
+ }
+ } else if (flush_pos == 0) {
+ // nothing could be flushed at all, we immediately give up without writing any data
+ return 0;
+ } else {
+ // we were partially successful, we shift left and try again
+ cxBufferShiftLeft(buffer, flush_pos);
+ return cxBufferWrite(ptr, size, nitems, buffer);
+ }
+ } else {
+ memcpy(buffer->bytes + buffer->pos, ptr, len);
+ buffer->pos += len;
+ if (buffer->pos > buffer->size) {
+ buffer->size = buffer->pos;
+ }
+ return nitems_out;