aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Serialization
diff options
context:
space:
mode:
authorMike Mazur2009-03-16 00:12:25 +0000
committerMike Mazur2009-03-16 00:12:25 +0000
commitf28886e26d32eaf97180d91dcd42fa045990bdd0 (patch)
tree69f36a36c809c9961758897d43c85413b1d4dd77 /OpenSim/Framework/Serialization
parentThis patch improves MXP connect and disconnect functionality. (diff)
downloadopensim-SC-f28886e26d32eaf97180d91dcd42fa045990bdd0.zip
opensim-SC-f28886e26d32eaf97180d91dcd42fa045990bdd0.tar.gz
opensim-SC-f28886e26d32eaf97180d91dcd42fa045990bdd0.tar.bz2
opensim-SC-f28886e26d32eaf97180d91dcd42fa045990bdd0.tar.xz
Rename OpenSim.Framework.Archive to OpenSim.Framework.Serialization
Update using statements and prebuild.xml. Also trim trailing whitespace.
Diffstat (limited to 'OpenSim/Framework/Serialization')
-rw-r--r--OpenSim/Framework/Serialization/ArchiveConstants.cs133
-rw-r--r--OpenSim/Framework/Serialization/TarArchiveReader.cs218
-rw-r--r--OpenSim/Framework/Serialization/TarArchiveWriter.cs217
3 files changed, 568 insertions, 0 deletions
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs
new file mode 100644
index 0000000..d0a0985
--- /dev/null
+++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs
@@ -0,0 +1,133 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
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 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using OpenMetaverse;
30
31namespace OpenSim.Framework.Serialization
32{
33 /// <summary>
34 /// Constants for the archiving module
35 /// </summary>
36 public class ArchiveConstants
37 {
38 /// <summary>
39 /// The location of the archive control file
40 /// </summary>
41 public static readonly string CONTROL_FILE_PATH = "archive.xml";
42
43 /// <summary>
44 /// Path for the assets held in an archive
45 /// </summary>
46 public static readonly string ASSETS_PATH = "assets/";
47
48 /// <summary>
49 /// Path for the inventory data
50 /// </summary>
51 public static readonly string INVENTORY_PATH = "inventory/";
52
53 /// <summary>
54 /// Path for the prims file
55 /// </summary>
56 public static readonly string OBJECTS_PATH = "objects/";
57
58 /// <summary>
59 /// Path for terrains. Technically these may be assets, but I think it's quite nice to split them out.
60 /// </summary>
61 public static readonly string TERRAINS_PATH = "terrains/";
62
63 /// <summary>
64 /// Path for region settings.
65 /// </summary>
66 public static readonly string SETTINGS_PATH = "settings/";
67
68 /// <summary>
69 /// The character the separates the uuid from extension information in an archived asset filename
70 /// </summary>
71 public static readonly string ASSET_EXTENSION_SEPARATOR = "_";
72
73 /// <summary>
74 /// Used to separate components in an inventory node name
75 /// </summary>
76 public static readonly string INVENTORY_NODE_NAME_COMPONENT_SEPARATOR = "__";
77
78 /// <summary>
79 /// Extensions used for asset types in the archive
80 /// </summary>
81 public static readonly IDictionary<sbyte, string> ASSET_TYPE_TO_EXTENSION = new Dictionary<sbyte, string>();
82 public static readonly IDictionary<string, sbyte> EXTENSION_TO_ASSET_TYPE = new Dictionary<string, sbyte>();
83
84 static ArchiveConstants()
85 {
86 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Animation] = ASSET_EXTENSION_SEPARATOR + "animation.bvh";
87 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Bodypart] = ASSET_EXTENSION_SEPARATOR + "bodypart.txt";
88 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.CallingCard] = ASSET_EXTENSION_SEPARATOR + "callingcard.txt";
89 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Clothing] = ASSET_EXTENSION_SEPARATOR + "clothing.txt";
90 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Folder] = ASSET_EXTENSION_SEPARATOR + "folder.txt"; // Not sure if we'll ever see this
91 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Gesture] = ASSET_EXTENSION_SEPARATOR + "gesture.txt";
92 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg";
93 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga";
94 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt";
95 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this
96 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso";
97 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl";
98 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt";
99 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml";
100 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this
101 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this
102 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this
103 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg";
104 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav";
105 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2";
106 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga";
107 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this
108
109 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation;
110 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart;
111 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "callingcard.txt"] = (sbyte)AssetType.CallingCard;
112 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "clothing.txt"] = (sbyte)AssetType.Clothing;
113 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "folder.txt"] = (sbyte)AssetType.Folder;
114 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "gesture.txt"] = (sbyte)AssetType.Gesture;
115 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = (sbyte)AssetType.ImageJPEG;
116 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = (sbyte)AssetType.ImageTGA;
117 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = (sbyte)AssetType.Landmark;
118 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = (sbyte)AssetType.LostAndFoundFolder;
119 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = (sbyte)AssetType.LSLBytecode;
120 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = (sbyte)AssetType.LSLText;
121 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = (sbyte)AssetType.Notecard;
122 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = (sbyte)AssetType.Object;
123 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = (sbyte)AssetType.RootFolder;
124 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = (sbyte)AssetType.Simstate;
125 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = (sbyte)AssetType.SnapshotFolder;
126 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = (sbyte)AssetType.Sound;
127 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = (sbyte)AssetType.SoundWAV;
128 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture;
129 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA;
130 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder;
131 }
132 }
133}
diff --git a/OpenSim/Framework/Serialization/TarArchiveReader.cs b/OpenSim/Framework/Serialization/TarArchiveReader.cs
new file mode 100644
index 0000000..da5703f
--- /dev/null
+++ b/OpenSim/Framework/Serialization/TarArchiveReader.cs
@@ -0,0 +1,218 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
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 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using System.Text;
32using log4net;
33
34namespace OpenSim.Framework.Serialization
35{
36 /// <summary>
37 /// Temporary code to do the bare minimum required to read a tar archive for our purposes
38 /// </summary>
39 public class TarArchiveReader
40 {
41 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 public enum TarEntryType
44 {
45 TYPE_UNKNOWN = 0,
46 TYPE_NORMAL_FILE = 1,
47 TYPE_HARD_LINK = 2,
48 TYPE_SYMBOLIC_LINK = 3,
49 TYPE_CHAR_SPECIAL = 4,
50 TYPE_BLOCK_SPECIAL = 5,
51 TYPE_DIRECTORY = 6,
52 TYPE_FIFO = 7,
53 TYPE_CONTIGUOUS_FILE = 8,
54 }
55
56 protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding();
57
58 /// <summary>
59 /// Binary reader for the underlying stream
60 /// </summary>
61 protected BinaryReader m_br;
62
63 /// <summary>
64 /// Used to trim off null chars
65 /// </summary>
66 protected char[] m_nullCharArray = new char[] { '\0' };
67
68 /// <summary>
69 /// Generate a tar reader which reads from the given stream.
70 /// </summary>
71 /// <param name="s"></param>
72 public TarArchiveReader(Stream s)
73 {
74 m_br = new BinaryReader(s);
75 }
76
77 /// <summary>
78 /// Read the next entry in the tar file.
79 /// </summary>
80 /// <param name="filePath"></param>
81 /// <returns>the data for the entry. Returns null if there are no more entries</returns>
82 public byte[] ReadEntry(out string filePath, out TarEntryType entryType)
83 {
84 filePath = String.Empty;
85 entryType = TarEntryType.TYPE_UNKNOWN;
86 TarHeader header = ReadHeader();
87
88 if (null == header)
89 return null;
90
91 entryType = header.EntryType;
92 filePath = header.FilePath;
93 return ReadData(header.FileSize);
94 }
95
96 /// <summary>
97 /// Read the next 512 byte chunk of data as a tar header.
98 /// </summary>
99 /// <returns>A tar header struct. null if we have reached the end of the archive.</returns>
100 protected TarHeader ReadHeader()
101 {
102 byte[] header = m_br.ReadBytes(512);
103
104 // If we've reached the end of the archive we'll be in null block territory, which means
105 // the next byte will be 0
106 if (header[0] == 0)
107 return null;
108
109 TarHeader tarHeader = new TarHeader();
110
111 // If we're looking at a GNU tar long link then extract the long name and pull up the next header
112 if (header[156] == (byte)'L')
113 {
114 int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11);
115 tarHeader.FilePath = m_asciiEncoding.GetString(ReadData(longNameLength));
116 //m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath);
117 header = m_br.ReadBytes(512);
118 }
119 else
120 {
121 tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100);
122 tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
123 //m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath);
124 }
125
126 tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
127
128 switch (header[156])
129 {
130 case 0:
131 tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
132 break;
133 case (byte)'0':
134 tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
135 break;
136 case (byte)'1':
137 tarHeader.EntryType = TarEntryType.TYPE_HARD_LINK;
138 break;
139 case (byte)'2':
140 tarHeader.EntryType = TarEntryType.TYPE_SYMBOLIC_LINK;
141 break;
142 case (byte)'3':
143 tarHeader.EntryType = TarEntryType.TYPE_CHAR_SPECIAL;
144 break;
145 case (byte)'4':
146 tarHeader.EntryType = TarEntryType.TYPE_BLOCK_SPECIAL;
147 break;
148 case (byte)'5':
149 tarHeader.EntryType = TarEntryType.TYPE_DIRECTORY;
150 break;
151 case (byte)'6':
152 tarHeader.EntryType = TarEntryType.TYPE_FIFO;
153 break;
154 case (byte)'7':
155 tarHeader.EntryType = TarEntryType.TYPE_CONTIGUOUS_FILE;
156 break;
157 }
158
159 return tarHeader;
160 }
161
162 /// <summary>
163 /// Read data following a header
164 /// </summary>
165 /// <param name="fileSize"></param>
166 /// <returns></returns>
167 protected byte[] ReadData(int fileSize)
168 {
169 byte[] data = m_br.ReadBytes(fileSize);
170
171 //m_log.DebugFormat("[TAR ARCHIVE READER]: fileSize {0}", fileSize);
172
173 // Read the rest of the empty padding in the 512 byte block
174 if (fileSize % 512 != 0)
175 {
176 int paddingLeft = 512 - (fileSize % 512);
177
178 //m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft);
179
180 m_br.ReadBytes(paddingLeft);
181 }
182
183 return data;
184 }
185
186 public void Close()
187 {
188 m_br.Close();
189 }
190
191 /// <summary>
192 /// Convert octal bytes to a decimal representation
193 /// </summary>
194 /// <param name="bytes"></param>
195 /// <returns></returns>
196 public static int ConvertOctalBytesToDecimal(byte[] bytes, int startIndex, int count)
197 {
198 string oString = m_asciiEncoding.GetString(bytes, startIndex, count);
199
200 int d = 0;
201
202 foreach (char c in oString)
203 {
204 d <<= 3;
205 d |= c - '0';
206 }
207
208 return d;
209 }
210 }
211
212 public class TarHeader
213 {
214 public string FilePath;
215 public int FileSize;
216 public TarArchiveReader.TarEntryType EntryType;
217 }
218}
diff --git a/OpenSim/Framework/Serialization/TarArchiveWriter.cs b/OpenSim/Framework/Serialization/TarArchiveWriter.cs
new file mode 100644
index 0000000..d319b0b
--- /dev/null
+++ b/OpenSim/Framework/Serialization/TarArchiveWriter.cs
@@ -0,0 +1,217 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
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 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Text;
32
33namespace OpenSim.Framework.Serialization
34{
35 /// <summary>
36 /// Temporary code to produce a tar archive in tar v7 format
37 /// </summary>
38 public class TarArchiveWriter
39 {
40 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding();
43
44 /// <summary>
45 /// Binary writer for the underlying stream
46 /// </summary>
47 protected BinaryWriter m_bw;
48
49 public TarArchiveWriter(Stream s)
50 {
51 m_bw = new BinaryWriter(s);
52 }
53
54 /// <summary>
55 /// Write a directory entry to the tar archive. We can only handle one path level right now!
56 /// </summary>
57 /// <param name="dirName"></param>
58 public void WriteDir(string dirName)
59 {
60 // Directories are signalled by a final /
61 if (!dirName.EndsWith("/"))
62 dirName += "/";
63
64 WriteFile(dirName, new byte[0]);
65 }
66
67 /// <summary>
68 /// Write a file to the tar archive
69 /// </summary>
70 /// <param name="filePath"></param>
71 /// <param name="data"></param>
72 public void WriteFile(string filePath, string data)
73 {
74 WriteFile(filePath, m_asciiEncoding.GetBytes(data));
75 }
76
77 /// <summary>
78 /// Write a file to the tar archive
79 /// </summary>
80 /// <param name="filePath"></param>
81 /// <param name="data"></param>
82 public void WriteFile(string filePath, byte[] data)
83 {
84 if (filePath.Length > 100)
85 WriteEntry("././@LongLink", m_asciiEncoding.GetBytes(filePath), 'L');
86
87 char fileType;
88
89 if (filePath.EndsWith("/"))
90 {
91 fileType = '5';
92 }
93 else
94 {
95 fileType = '0';
96 }
97
98 WriteEntry(filePath, data, fileType);
99 }
100
101 /// <summary>
102 /// Finish writing the raw tar archive data to a stream. The stream will be closed on completion.
103 /// </summary>
104 /// <param name="s">Stream to which to write the data</param>
105 /// <returns></returns>
106 public void Close()
107 {
108 //m_log.Debug("[TAR ARCHIVE WRITER]: Writing final consecutive 0 blocks");
109
110 // Write two consecutive 0 blocks to end the archive
111 byte[] finalZeroPadding = new byte[1024];
112 m_bw.Write(finalZeroPadding);
113
114 m_bw.Flush();
115 m_bw.Close();
116 }
117
118 public static byte[] ConvertDecimalToPaddedOctalBytes(int d, int padding)
119 {
120 string oString = "";
121
122 while (d > 0)
123 {
124 oString = Convert.ToString((byte)'0' + d & 7) + oString;
125 d >>= 3;
126 }
127
128 while (oString.Length < padding)
129 {
130 oString = "0" + oString;
131 }
132
133 byte[] oBytes = m_asciiEncoding.GetBytes(oString);
134
135 return oBytes;
136 }
137
138 /// <summary>
139 /// Write a particular entry
140 /// </summary>
141 /// <param name="filePath"></param>
142 /// <param name="data"></param>
143 /// <param name="fileType"></param>
144 protected void WriteEntry(string filePath, byte[] data, char fileType)
145 {
146 byte[] header = new byte[512];
147
148 // file path field (100)
149 byte[] nameBytes = m_asciiEncoding.GetBytes(filePath);
150 int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length;
151 Array.Copy(nameBytes, header, nameSize);
152
153 // file mode (8)
154 byte[] modeBytes = m_asciiEncoding.GetBytes("0000777");
155 Array.Copy(modeBytes, 0, header, 100, 7);
156
157 // owner user id (8)
158 byte[] ownerIdBytes = m_asciiEncoding.GetBytes("0000764");
159 Array.Copy(ownerIdBytes, 0, header, 108, 7);
160
161 // group user id (8)
162 byte[] groupIdBytes = m_asciiEncoding.GetBytes("0000764");
163 Array.Copy(groupIdBytes, 0, header, 116, 7);
164
165 // file size in bytes (12)
166 int fileSize = data.Length;
167 //m_log.DebugFormat("[TAR ARCHIVE WRITER]: File size of {0} is {1}", filePath, fileSize);
168
169 byte[] fileSizeBytes = ConvertDecimalToPaddedOctalBytes(fileSize, 11);
170
171 Array.Copy(fileSizeBytes, 0, header, 124, 11);
172
173 // last modification time (12)
174 byte[] lastModTimeBytes = m_asciiEncoding.GetBytes("11017037332");
175 Array.Copy(lastModTimeBytes, 0, header, 136, 11);
176
177 // entry type indicator (1)
178 header[156] = m_asciiEncoding.GetBytes(new char[] { fileType })[0];
179
180 Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 329, 7);
181 Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 337, 7);
182
183 // check sum for header block (8) [calculated last]
184 Array.Copy(m_asciiEncoding.GetBytes(" "), 0, header, 148, 8);
185
186 int checksum = 0;
187 foreach (byte b in header)
188 {
189 checksum += b;
190 }
191
192 //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Decimal header checksum is {0}", checksum);
193
194 byte[] checkSumBytes = ConvertDecimalToPaddedOctalBytes(checksum, 6);
195
196 Array.Copy(checkSumBytes, 0, header, 148, 6);
197
198 header[154] = 0;
199
200 // Write out header
201 m_bw.Write(header);
202
203 // Write out data
204 m_bw.Write(data);
205
206 if (data.Length % 512 != 0)
207 {
208 int paddingRequired = 512 - (data.Length % 512);
209
210 //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired);
211
212 byte[] padding = new byte[paddingRequired];
213 m_bw.Write(padding);
214 }
215 }
216 }
217}