corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.IO;
29 using System.Reflection;
30 using System.Text;
31  
32 namespace OpenMetaverse.Assets
33 {
34 /// <summary>
35 /// Temporary code to do the bare minimum required to read a tar archive for our purposes
36 /// </summary>
37 public class TarArchiveReader
38 {
39 public enum TarEntryType
40 {
41 TYPE_UNKNOWN = 0,
42 TYPE_NORMAL_FILE = 1,
43 TYPE_HARD_LINK = 2,
44 TYPE_SYMBOLIC_LINK = 3,
45 TYPE_CHAR_SPECIAL = 4,
46 TYPE_BLOCK_SPECIAL = 5,
47 TYPE_DIRECTORY = 6,
48 TYPE_FIFO = 7,
49 TYPE_CONTIGUOUS_FILE = 8,
50 }
51  
52 protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding();
53  
54 /// <summary>
55 /// Binary reader for the underlying stream
56 /// </summary>
57 protected BinaryReader m_br;
58  
59 /// <summary>
60 /// Used to trim off null chars
61 /// </summary>
62 protected static readonly char[] m_nullCharArray = new char[] { '\0' };
63  
64 /// <summary>
65 /// Used to trim off space chars
66 /// </summary>
67 protected static readonly char[] m_spaceCharArray = new char[] { ' ' };
68  
69 /// <summary>
70 /// Generate a tar reader which reads from the given stream.
71 /// </summary>
72 /// <param name="s"></param>
73 public TarArchiveReader(Stream s)
74 {
75 m_br = new BinaryReader(s);
76 }
77  
78 /// <summary>
79 /// Read the next entry in the tar file.
80 /// </summary>
81 /// <param name="filePath"></param>
82 /// <param name="entryType"></param>
83 /// <returns>the data for the entry. Returns null if there are no more entries</returns>
84 public byte[] ReadEntry(out string filePath, out TarEntryType entryType)
85 {
86 filePath = String.Empty;
87 entryType = TarEntryType.TYPE_UNKNOWN;
88 TarHeader header = ReadHeader();
89  
90 if (null == header)
91 return null;
92  
93 entryType = header.EntryType;
94 filePath = header.FilePath;
95 return ReadData(header.FileSize);
96 }
97  
98 /// <summary>
99 /// Read the next 512 byte chunk of data as a tar header.
100 /// </summary>
101 /// <returns>A tar header struct. null if we have reached the end of the archive.</returns>
102 protected TarHeader ReadHeader()
103 {
104 byte[] header = m_br.ReadBytes(512);
105  
106 // If we've reached the end of the archive we'll be in null block territory, which means
107 // the next byte will be 0
108 if (header[0] == 0)
109 return null;
110  
111 TarHeader tarHeader = new TarHeader();
112  
113 // If we're looking at a GNU tar long link then extract the long name and pull up the next header
114 if (header[156] == (byte)'L')
115 {
116 int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11);
117 tarHeader.FilePath = m_asciiEncoding.GetString(ReadData(longNameLength));
118 //m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath);
119 header = m_br.ReadBytes(512);
120 }
121 else
122 {
123 tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100);
124 tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
125 //m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath);
126 }
127  
128 tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
129  
130 switch (header[156])
131 {
132 case 0:
133 tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
134 break;
135 case (byte)'0':
136 tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
137 break;
138 case (byte)'1':
139 tarHeader.EntryType = TarEntryType.TYPE_HARD_LINK;
140 break;
141 case (byte)'2':
142 tarHeader.EntryType = TarEntryType.TYPE_SYMBOLIC_LINK;
143 break;
144 case (byte)'3':
145 tarHeader.EntryType = TarEntryType.TYPE_CHAR_SPECIAL;
146 break;
147 case (byte)'4':
148 tarHeader.EntryType = TarEntryType.TYPE_BLOCK_SPECIAL;
149 break;
150 case (byte)'5':
151 tarHeader.EntryType = TarEntryType.TYPE_DIRECTORY;
152 break;
153 case (byte)'6':
154 tarHeader.EntryType = TarEntryType.TYPE_FIFO;
155 break;
156 case (byte)'7':
157 tarHeader.EntryType = TarEntryType.TYPE_CONTIGUOUS_FILE;
158 break;
159 }
160  
161 return tarHeader;
162 }
163  
164 /// <summary>
165 /// Read data following a header
166 /// </summary>
167 /// <param name="fileSize"></param>
168 /// <returns></returns>
169 protected byte[] ReadData(int fileSize)
170 {
171 byte[] data = m_br.ReadBytes(fileSize);
172  
173 //m_log.DebugFormat("[TAR ARCHIVE READER]: fileSize {0}", fileSize);
174  
175 // Read the rest of the empty padding in the 512 byte block
176 if (fileSize % 512 != 0)
177 {
178 int paddingLeft = 512 - (fileSize % 512);
179  
180 //m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft);
181  
182 m_br.ReadBytes(paddingLeft);
183 }
184  
185 return data;
186 }
187  
188 public void Close()
189 {
190 m_br.Close();
191 }
192  
193 /// <summary>
194 /// Convert octal bytes to a decimal representation
195 /// </summary>
196 /// <param name="bytes"></param>
197 /// <param name="count"></param>
198 /// <param name="startIndex"></param>
199 /// <returns></returns>
200 public static int ConvertOctalBytesToDecimal(byte[] bytes, int startIndex, int count)
201 {
202 // Trim leading white space: ancient tars do that instead
203 // of leading 0s :-( don't ask. really.
204 string oString = m_asciiEncoding.GetString(bytes, startIndex, count).TrimStart(m_spaceCharArray);
205  
206 int d = 0;
207  
208 foreach (char c in oString)
209 {
210 d <<= 3;
211 d |= c - '0';
212 }
213  
214 return d;
215 }
216 }
217  
218 public class TarHeader
219 {
220 public string FilePath;
221 public int FileSize;
222 public TarArchiveReader.TarEntryType EntryType;
223 }
224 }