1//----------------------------------------------------------------------
2//  This software is part of the OpenBeOS distribution and is covered
3//  by the MIT License.
4//
5//  Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
6//----------------------------------------------------------------------
7
8/*! \file PositionIOStream.cpp
9*/
10
11#include "PositionIOStream.h"
12
13#include <stdlib.h>
14#include <string.h>
15
16PositionIOStream::PositionIOStream(BPositionIO &stream)
17	: fStream(stream)
18{
19}
20
21ssize_t
22PositionIOStream::Read(void *buffer, size_t size)
23{
24	return fStream.Read(buffer, size);
25}
26
27ssize_t
28PositionIOStream::ReadAt(off_t pos, void *buffer, size_t size)
29{
30	return fStream.ReadAt(pos, buffer, size);
31}
32
33ssize_t
34PositionIOStream::Write(const void *buffer, size_t size)
35{
36	return fStream.Write(buffer, size);
37}
38
39ssize_t
40PositionIOStream::WriteAt(off_t pos, const void *buffer, size_t size)
41{
42	return fStream.WriteAt(pos, buffer, size);
43}
44
45/*! \brief Writes \a size bytes worth of data from \a data at the current
46	position in the file, incrementing the file's position marker as it goes.
47*/
48ssize_t
49PositionIOStream::Write(BDataIO &data, size_t size)
50{
51	status_t error = kBufferSize > 0 ? B_OK : B_BAD_VALUE;
52	size_t bytes = 0;
53	if (!error) {
54		void *buffer = malloc(kBufferSize);
55		error = buffer ? B_OK : B_NO_MEMORY;
56		if (!error) {
57			// Fudge the buffer size from here out if the requested
58			// number of bytes to write is smaller than the buffer
59			size_t bufferSize = (size < kBufferSize ? size : kBufferSize);
60			// Zero
61			memset(buffer, 0, bufferSize);
62			// Write
63			while (bytes < size) {
64				ssize_t bytesRead = data.Read(buffer, bufferSize);
65				if (bytesRead >= 0) {
66					ssize_t bytesWritten = fStream.Write(buffer, bytesRead);
67					if (bytesWritten >= 0) {
68						bytes += bytesWritten;
69					} else {
70						error = status_t(bytesWritten);
71						break;
72					}
73				} else {
74					error = status_t(bytesRead);
75					break;
76				}
77			}
78		}
79		free(buffer);
80	}
81	return error ? ssize_t(error) : ssize_t(bytes);
82}
83
84/*! \brief Writes \a size bytes worth of data from \a data at position
85	\a pos in the file without incrementing the file's position marker.
86*/
87ssize_t
88PositionIOStream::WriteAt(off_t pos, BDataIO &data, size_t size)
89{
90	status_t error = kBufferSize > 0 ? B_OK : B_BAD_VALUE;
91	size_t bytes = 0;
92	if (!error) {
93		void *buffer = malloc(kBufferSize);
94		error = buffer ? B_OK : B_NO_MEMORY;
95		if (!error) {
96			// Fudge the buffer size from here out if the requested
97			// number of bytes to write is smaller than the buffer
98			size_t bufferSize = (size < kBufferSize ? size : kBufferSize);
99			// Zero
100			memset(buffer, 0, bufferSize);
101			// Write
102			while (bytes < size) {
103				ssize_t bytesRead = data.Read(buffer, bufferSize);
104				if (bytesRead >= 0) {
105					ssize_t bytesWritten = fStream.WriteAt(pos, buffer, bytesRead);
106					if (bytesWritten >= 0) {
107						bytes += bytesWritten;
108						pos += bytesWritten;
109					} else {
110						error = status_t(bytesWritten);
111						break;
112					}
113				} else {
114					error = status_t(bytesRead);
115					break;
116				}
117			}
118		}
119		free(buffer);
120	}
121	return error ? ssize_t(error) : ssize_t(bytes);
122}
123
124/*! \brief Writes \a size bytes worth of zeros at the current position
125	in the file, incrementing the file's position marker as it goes.
126*/
127ssize_t
128PositionIOStream::Zero(size_t size)
129{
130	status_t error = kBufferSize > 0 ? B_OK : B_BAD_VALUE;
131	size_t bytes = 0;
132	if (!error) {
133		void *buffer = malloc(kBufferSize);
134		error = buffer ? B_OK : B_NO_MEMORY;
135		if (!error) {
136			// Fudge the buffer size from here out if the requested
137			// number of bytes to write is smaller than the buffer
138			size_t bufferSize = (size < kBufferSize ? size : kBufferSize);
139			// Zero
140			memset(buffer, 0, bufferSize);
141			// Write
142			while (bytes < size) {
143				ssize_t bytesWritten = fStream.Write(buffer, bufferSize);
144				if (bytesWritten >= 0) {
145					bytes += bytesWritten;
146				} else {
147					error = status_t(bytesWritten);
148					break;
149				}
150			}
151		}
152		free(buffer);
153	}
154	return error ? ssize_t(error) : ssize_t(bytes);
155}
156
157/*! \brief Writes \a size bytes worth of zeros at position \a pos
158	in the file without incrementing the file's position marker.
159*/
160ssize_t
161PositionIOStream::ZeroAt(off_t pos, size_t size)
162{
163	status_t error = kBufferSize > 0 ? B_OK : B_BAD_VALUE;
164	size_t bytes = 0;
165	if (!error) {
166		void *buffer = malloc(kBufferSize);
167		error = buffer ? B_OK : B_NO_MEMORY;
168		if (!error) {
169			// Fudge the buffer size from here out if the requested
170			// number of bytes to write is smaller than the buffer
171			size_t bufferSize = (size < kBufferSize ? size : kBufferSize);
172			// Zero
173			memset(buffer, 0, bufferSize);
174			// Write
175			while (bytes < size) {
176				ssize_t bytesWritten = fStream.WriteAt(pos, buffer, bufferSize);
177				if (bytesWritten >= 0) {
178					bytes += bytesWritten;
179					pos += bytesWritten;
180				} else {
181					error = status_t(bytesWritten);
182					break;
183				}
184			}
185		}
186		free(buffer);
187	}
188	return error ? ssize_t(error) : ssize_t(bytes);
189}
190
191off_t
192PositionIOStream::Seek(off_t position, uint32 seek_mode)
193{
194	return fStream.Seek(position, seek_mode);
195}
196
197off_t
198PositionIOStream::Position() const
199{
200	return fStream.Position();
201}
202
203status_t
204PositionIOStream::SetSize(off_t size)
205{
206	return fStream.SetSize(size);
207}
208