1:   // TarOutputStream.cs
2:   // Copyright (C) 2001 Mike Krueger
3:   //
4:   // This program is free software; you can redistribute it and/or
5:   // modify it under the terms of the GNU General Public License
6:   // as published by the Free Software Foundation; either version 2
7:   // of the License, or (at your option) any later version.
8:   //
9:   // This program is distributed in the hope that it will be useful,
10:   // but WITHOUT ANY WARRANTY; without even the implied warranty of
11:   // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12:   // GNU General Public License for more details.
13:   //
14:   // You should have received a copy of the GNU General Public License
15:   // along with this program; if not, write to the Free Software
16:   // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17:   //
18:   // Linking this library statically or dynamically with other modules is
19:   // making a combined work based on this library.  Thus, the terms and
20:   // conditions of the GNU General Public License cover the whole
21:   // combination.
22:   // 
23:   // As a special exception, the copyright holders of this library give you
24:   // permission to link this library with independent modules to produce an
25:   // executable, regardless of the license terms of these independent
26:   // modules, and to copy and distribute the resulting executable under
27:   // terms of your choice, provided that you also meet, for each linked
28:   // independent module, the terms and conditions of the license of that
29:   // module.  An independent module is a module which is not derived from
30:   // or based on this library.  If you modify this library, you may extend
31:   // this exception to your version of the library, but you are not
32:   // obligated to do so.  If you do not wish to do so, delete this
33:   // exception statement from your version.
34:  
35:   using System;
36:   using System.IO;
37:   using System.Text;
38:  
39:   namespace ICSharpCode.SharpZipLib.Tar {
40:       
41:       /// <summary>
42:       /// The TarOutputStream writes a UNIX tar archive as an OutputStream.
43:       /// Methods are provided to put entries, and then write their contents
44:       /// by writing to this stream using write().
45:       /// </summary>
46:       /// public
47:       public class TarOutputStream : Stream
48:       {
49:           protected bool   debug;
50:           protected int    currSize;
51:           protected int    currBytes;
52:           protected byte[] recordBuf;
53:           protected int    assemLen;
54:           protected byte[] assemBuf;
55:           
56:           protected TarBuffer buffer;
57:           protected Stream    outputStream;
58:           
59:           /// <summary>
60:           /// I needed to implement the abstract member.
61:           /// </summary>
62:           public override bool CanRead {
63:               get {
64:                   return outputStream.CanRead;
65:               }
66:           }
67:           
68:           /// <summary>
69:           /// I needed to implement the abstract member.
70:           /// </summary>
71:           public override bool CanSeek {
72:               get {
73:                   return outputStream.CanSeek;
74:               }
75:           }
76:           
77:           /// <summary>
78:           /// I needed to implement the abstract member.
79:           /// </summary>
80:           public override bool CanWrite {
81:               get {
82:                   return outputStream.CanWrite;
83:               }
84:           }
85:           
86:           /// <summary>
87:           /// I needed to implement the abstract member.
88:           /// </summary>
89:           public override long Length {
90:               get {
91:                   return outputStream.Length;
92:               }
93:           }
94:           
95:           /// <summary>
96:           /// I needed to implement the abstract member.
97:           /// </summary>
98:           public override long Position {
99:               get {
100:                   return outputStream.Position;
101:               }
102:               set {
103:                   outputStream.Position value;
104:               }
105:           }
106:           
107:           /// <summary>
108:           /// I needed to implement the abstract member.
109:           /// </summary>
110:           public override long Seek(long offsetSeekOrigin origin)
111:           {
112:               return outputStream.Seek(offsetorigin);
113:           }
114:           
115:           /// <summary>
116:           /// I needed to implement the abstract member.
117:           /// </summary>
118:           public override void SetLength(long val)
119:           {
120:               outputStream.SetLength(val);
121:           }
122:           
123:           /// <summary>
124:           /// I needed to implement the abstract member.
125:           /// </summary>
126:           public override int ReadByte()
127:           {
128:               return outputStream.ReadByte();
129:           }
130:           
131:           /// <summary>
132:           /// I needed to implement the abstract member.
133:           /// </summary>
134:           public override int Read(byte[] bint offint len)
135:           {
136:               return outputStream.Read(bofflen);
137:           }
138:           
139:           public override void Flush()
140:           {
141:               outputStream.Flush();
142:           }
143:                   
144:           public TarOutputStream(Stream outputStreamthis(outputStreamTarBuffer.DEFAULT_BLKSIZETarBuffer.DEFAULT_RCDSIZE)
145:           {
146:           }
147:           
148:           public TarOutputStream(Stream outputStreamint blockSizethis(outputStreamblockSizeTarBuffer.DEFAULT_RCDSIZE)
149:           {
150:           }
151:           
152:           public TarOutputStream(Stream outputStreamint blockSizeint recordSize)
153:           {
154:               this.outputStream outputStream;
155:               this.buffer       TarBuffer.CreateOutputTarBuffer(outputStreamblockSizerecordSize);
156:               
157:               this.debug     false;
158:               this.assemLen  0;
159:               this.assemBuf  new byte[recordSize];
160:               this.recordBuf new byte[recordSize];
161:           }
162:           
163:           /// <summary>
164:           /// Sets the debugging flag.
165:           /// </summary>
166:           /// <param name = "debugF">
167:           /// True to turn on debugging.
168:           /// </param>
169:           public void SetDebug(bool debugF)
170:           {
171:               this.debug debugF;
172:               SetBufferDebug(debugF);
173:           }
174:           
175:           public void SetBufferDebug(bool debug)
176:           {
177:               this.buffer.SetDebug(debug);
178:           }
179:           
180:           /// <summary>
181:           /// Ends the TAR archive without closing the underlying OutputStream.
182:           /// The result is that the EOF record of nulls is written.
183:           /// </summary>
184:           public void Finish()
185:           {
186:               this.WriteEOFRecord();
187:           }
188:           
189:           /// <summary>
190:           /// Ends the TAR archive and closes the underlying OutputStream.
191:           /// This means that finish() is called followed by calling the
192:           /// TarBuffer's close().
193:           /// </summary>
194:           public override void Close()
195:           {
196:               this.Finish();
197:               this.buffer.Close();
198:           }
199:           
200:           /// <summary>
201:           /// Get the record size being used by this stream's TarBuffer.
202:           /// </summary>
203:           /// <returns>
204:           /// The TarBuffer record size.
205:           /// </returns>
206:           public int GetRecordSize()
207:           {
208:               return this.buffer.GetRecordSize();
209:           }
210:           
211:           /// <summary>
212:           /// Put an entry on the output stream. This writes the entry's
213:           /// header record and positions the output stream for writing
214:           /// the contents of the entry. Once this method is called, the
215:           /// stream is ready for calls to write() to write the entry's
216:           /// contents. Once the contents are written, closeEntry()
217:           /// <B>MUST</B> be called to ensure that all buffered data
218:           /// is completely written to the output stream.
219:           /// </summary>
220:           /// <param name="entry">
221:           /// The TarEntry to be written to the archive.
222:           /// </param>
223:           public void PutNextEntry(TarEntry entry)
224:           {
225:               if (entry.TarHeader.name.Length TarHeader.NAMELEN) {
226:                   throw new InvalidHeaderException("file name '" entry.TarHeader.name "' is too long ( > " TarHeader.NAMELEN " bytes )");
227:               }
228:               
229:               entry.WriteEntryHeader(this.recordBuf);
230:               this.buffer.WriteRecord(this.recordBuf);
231:               
232:               this.currBytes 0;
233:               
234:               this.currSize entry.IsDirectory (int)entry.Size;
235:           }
236:           
237:           /// <summary>
238:           /// Close an entry. This method MUST be called for all file
239:           /// entries that contain data. The reason is that we must
240:           /// buffer data written to the stream in order to satisfy
241:           /// the buffer's record based writes. Thus, there may be
242:           /// data fragments still being assembled that must be written
243:           /// to the output stream before this entry is closed and the
244:           /// next entry written.
245:           /// </summary>
246:           public void CloseEntry()
247:           {
248:               if (this.assemLen 0) {
249:                   for (int this.assemLenthis.assemBuf.Length; ++i) {
250:                       this.assemBuf[i] = 0;
251:                   }
252:                   
253:                   this.buffer.WriteRecord(this.assemBuf);
254:                   
255:                   this.currBytes += this.assemLen;
256:                   this.assemLen 0;
257:               }
258:               
259:               if (this.currBytes this.currSize) {
260:                   throw new IOException("entry closed at '" this.currBytes "' before the '" this.currSize "' bytes specified in the header were written");
261:               }
262:           }
263:           
264:           /// <summary>
265:           /// Writes a byte to the current tar archive entry.
266:           /// This method simply calls Write(byte[], int, int).
267:           /// </summary>
268:           /// <param name="b">
269:           /// The byte written.
270:           /// </param>
271:           public override void WriteByte(byte b)
272:           {
273:               this.Write(new byte[] { }, 01);
274:           }
275:           
276:           /// <summary>
277:           /// Writes bytes to the current tar archive entry. This method
278:           /// is aware of the current entry and will throw an exception if
279:           /// you attempt to write bytes past the length specified for the
280:           /// current entry. The method is also (painfully) aware of the
281:           /// record buffering required by TarBuffer, and manages buffers
282:           /// that are not a multiple of recordsize in length, including
283:           /// assembling records from small buffers.
284:           /// </summary>
285:           /// <param name = "wBuf">
286:           /// The buffer to write to the archive.
287:           /// </param>
288:           /// <param name = "wOffset">
289:           /// The offset in the buffer from which to get bytes.
290:           /// </param>
291:           /// <param name = "numToWrite">
292:           /// The number of bytes to write.
293:           /// </param>
294:           public override void Write(byte[] wBufint wOffsetint numToWrite)
295:           {
296:               if ((this.currBytes numToWrite) > this.currSize) {
297:                   throw new IOException("request to write '" numToWrite "' bytes exceeds size in header of '" this.currSize "' bytes");
298:               }
299:               
300:               //
301:               // We have to deal with assembly!!!
302:               // The programmer can be writing little 32 byte chunks for all
303:               // we know, and we must assemble complete records for writing.
304:               // REVIEW Maybe this should be in TarBuffer? Could that help to
305:               //        eliminate some of the buffer copying.
306:               //
307:               if (this.assemLen 0) {
308:                   if ((this.assemLen numToWrite ) >= this.recordBuf.Length) {
309:                       int aLen this.recordBuf.Length this.assemLen;
310:                       
311:                       Array.Copy(this.assemBuf0this.recordBuf0this.assemLen);
312:                       
313:                       Array.Copy(wBufwOffsetthis.recordBufthis.assemLenaLen);
314:                       
315:                       this.buffer.WriteRecord(this.recordBuf);
316:                       
317:                       this.currBytes += this.recordBuf.Length;
318:                       
319:                       wOffset    += aLen;
320:                       numToWrite -= aLen;
321:                       
322:                       this.assemLen 0;
323:                   else {// ( (this.assemLen + numToWrite ) < this.recordBuf.length )
324:                       Array.Copy(wBufwOffsetthis.assemBufthis.assemLennumToWrite);
325:                       wOffset       += numToWrite;
326:                       this.assemLen += numToWrite;
327:                       numToWrite -= numToWrite;
328:                   }
329:               }
330:               
331:               //
332:               // When we get here we have EITHER:
333:               //   o An empty "assemble" buffer.
334:               //   o No bytes to write (numToWrite == 0)
335:               //
336:               while (numToWrite 0) {
337:                   if (numToWrite this.recordBuf.Length) {
338:                       Array.Copy(wBufwOffsetthis.assemBufthis.assemLennumToWrite);
339:                       this.assemLen += numToWrite;
340:                       break;
341:                   }
342:                   
343:                   this.buffer.WriteRecord(wBufwOffset);
344:                   
345:                   int num this.recordBuf.Length;
346:                   this.currBytes += num;
347:                   numToWrite     -= num;
348:                   wOffset        += num;
349:               }
350:           }
351:           
352:           /// <summary>
353:           /// Write an EOF (end of archive) record to the tar archive.
354:           /// An EOF record consists of a record of all zeros.
355:           /// </summary>
356:           void WriteEOFRecord()
357:           {
358:               for (int 0this.recordBuf.Length; ++i) {
359:                   this.recordBuf[i] = 0;
360:               }
361:               this.buffer.WriteRecord(this.recordBuf);
362:           }
363:       }
364:   }
365:  
366:   /* The original Java file had this header:
367:       ** Authored by Timothy Gerard Endres
368:       ** <mailto:time@gjt.org>  <http://www.trustice.com>
369:       **
370:       ** This work has been placed into the public domain.
371:       ** You may use this work in any way and for any purpose you wish.
372:       **
373:       ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
374:       ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
375:       ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
376:       ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
377:       ** REDISTRIBUTION OF THIS SOFTWARE.
378:       **
379:       */

This page was automatically generated by SharpDevelop.