1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2 // Licensed under the MIT License:
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 
22 module capnproto.BufferedOutputStreamWrapper;
23 
24 import java.io.IOException;
25 import java.nio.ByteBuffer;
26 import java.nio.channels.WritableByteChannel;
27 
28 import capnproto.BufferedOutputStream;
29 
30 final class BufferedOutputStreamWrapper : BufferedOutputStream
31 {
32 public: //Methods.
33 	this(WritableByteChannel w)
34 	{
35 		this.inner = w;
36 		this.buf = ByteBuffer(new ubyte[](8192));
37 	}
38 	
39 	size_t write(ref ByteBuffer src)
40 	{
41 		auto available = this.buf.remaining();
42 		auto size = src.remaining();
43 		if(size <= available)
44 			this.buf.put!ByteBuffer(src);
45 		else if(size <= this.buf.capacity())
46 		{
47 			//# Too much for this buffer, but not a full buffer's worth,
48 			//# so we'll go ahead and copy.
49 			auto slice = src.slice();
50 			slice.limit = available;
51 			this.buf.put!ByteBuffer(slice);
52 			
53 			this.buf.rewind();
54 			while(!this.buf.empty())
55 				this.inner.write(this.buf);
56 			this.buf.rewind();
57 			
58 			src.position += available;
59 			this.buf.put!ByteBuffer(src);
60 		}
61 		else
62 		{
63 			//# Writing so much data that we might as well write
64 			//# directly to avoid a copy.
65 			auto pos = this.buf.position;
66 			this.buf.rewind();
67 			auto slice = this.buf.slice();
68 			slice.limit = pos;
69 			while(!slice.empty())
70 				this.inner.write(slice);
71 			while(!src.empty())
72 				this.inner.write(src);
73 		}
74 		return size;
75 	}
76 	
77 	ByteBuffer* getWriteBuffer()
78 	{
79 		return &this.buf;
80 	}
81 	
82 	void close()
83 	{
84 		this.inner.close();
85 	}
86 	
87 	bool isOpen()
88 	{
89 		return this.inner.isOpen();
90 	}
91 	
92 	void flush()
93 	{
94 		auto pos = this.buf.position;
95 		this.buf.rewind();
96 		this.buf.limit = pos;
97 		this.inner.write(this.buf);
98 		this.buf.clear();
99 	}
100 
101 private: //Variables.
102 	WritableByteChannel inner;
103 	ByteBuffer buf;
104 }