1
1
// source https://gist.github.com/Su-s/438be493ae692318c73e30367cbc5c2a
2
+ // updated source https://gist.github.com/Matheos96/da8990030dfe3e27b0a48722042d9c0b
2
3
3
4
using System ;
4
5
using System . IO ;
@@ -16,7 +17,10 @@ public class Tar
16
17
/// <param name="outputDir">Output directory to write the files.</param>
17
18
public static void ExtractTarGz ( string filename , string outputDir )
18
19
{
19
- using ( var stream = File . OpenRead ( filename ) ) ExtractTarGz ( stream , outputDir ) ;
20
+ using ( var stream = File . OpenRead ( filename ) )
21
+ {
22
+ ExtractTarGz ( stream , outputDir ) ;
23
+ }
20
24
}
21
25
22
26
/// <summary>
@@ -26,9 +30,25 @@ public static void ExtractTarGz(string filename, string outputDir)
26
30
/// <param name="outputDir">Output directory to write the files.</param>
27
31
public static void ExtractTarGz ( Stream stream , string outputDir )
28
32
{
29
- using ( var gzip = new GZipStream ( stream , CompressionMode . Decompress ) )
33
+ int read ;
34
+ const int chunk = 4096 ;
35
+ var buffer = new byte [ chunk ] ;
36
+
37
+ // A GZipStream is not seekable, so copy it first to a MemoryStream
38
+ using ( var gzipStream = new GZipStream ( stream , CompressionMode . Decompress ) )
30
39
{
31
- ExtractTar ( gzip , outputDir ) ;
40
+ using ( var memStream = new MemoryStream ( ) )
41
+ {
42
+ //For .NET 6+
43
+ while ( ( read = gzipStream . Read ( buffer , 0 , buffer . Length ) ) > 0 )
44
+ {
45
+ memStream . Write ( buffer , 0 , read ) ;
46
+ }
47
+ memStream . Seek ( 0 , SeekOrigin . Begin ) ;
48
+
49
+ //ExtractTar(gzip, outputDir);
50
+ ExtractTar ( memStream , outputDir ) ;
51
+ }
32
52
}
33
53
}
34
54
@@ -40,7 +60,9 @@ public static void ExtractTarGz(Stream stream, string outputDir)
40
60
public static void ExtractTar ( string filename , string outputDir )
41
61
{
42
62
using ( var stream = File . OpenRead ( filename ) )
63
+ {
43
64
ExtractTar ( stream , outputDir ) ;
65
+ }
44
66
}
45
67
46
68
/// <summary>
@@ -51,78 +73,115 @@ public static void ExtractTar(string filename, string outputDir)
51
73
public static void ExtractTar ( Stream stream , string outputDir )
52
74
{
53
75
var buffer = new byte [ 100 ] ;
54
- // store current position here
55
- long pos = 0 ;
76
+ var longFileName = string . Empty ;
56
77
while ( true )
57
78
{
58
- pos += stream . Read ( buffer , 0 , 100 ) ;
59
- var name = Encoding . ASCII . GetString ( buffer ) . Trim ( '\0 ' ) ;
60
- if ( String . IsNullOrWhiteSpace ( name ) ) break ;
61
- FakeSeekForward ( stream , 24 ) ;
62
- pos += 24 ;
79
+ stream . Read ( buffer , 0 , 100 ) ;
80
+ string name = string . IsNullOrEmpty ( longFileName ) ? Encoding . ASCII . GetString ( buffer ) . Trim ( '\0 ' ) : longFileName ; //Use longFileName if we have one read
63
81
64
- pos += stream . Read ( buffer , 0 , 12 ) ;
82
+ if ( String . IsNullOrWhiteSpace ( name ) ) break ;
83
+ stream . Seek ( 24 , SeekOrigin . Current ) ;
84
+ stream . Read ( buffer , 0 , 12 ) ;
65
85
var size = Convert . ToInt64 ( Encoding . UTF8 . GetString ( buffer , 0 , 12 ) . Trim ( '\0 ' ) . Trim ( ) , 8 ) ;
66
- FakeSeekForward ( stream , 376 ) ;
67
- pos += 376 ;
86
+ stream . Seek ( 20 , SeekOrigin . Current ) ; //Move head to typeTag byte
87
+ var typeTag = stream . ReadByte ( ) ;
88
+ stream . Seek ( 355L , SeekOrigin . Current ) ; //Move head to beginning of data (byte 512)
89
+
90
+ if ( typeTag == 'L' )
91
+ {
92
+ //If Type Tag is 'L' we have a filename that is longer than the 100 bytes reserved for it in the header.
93
+ //We read it here and save it temporarily as it will be the file name of the next block where the actual data is
94
+ var buf = new byte [ size ] ;
95
+ stream . Read ( buf , 0 , buf . Length ) ;
96
+ longFileName = Encoding . ASCII . GetString ( buf ) . Trim ( '\0 ' ) ;
97
+ }
98
+ else
99
+ {
100
+ longFileName = string . Empty ; //Reset longFileName if current entry is not indicating one
68
101
69
- var output = Path . Combine ( outputDir , name ) ;
102
+ var output = Path . Combine ( outputDir , name ) ;
70
103
71
- // only include these folders
72
- var include = ( output . IndexOf ( "package/ProjectData~/Assets/" ) > - 1 ) ;
73
- include |= ( output . IndexOf ( "package/ProjectData~/ProjectSettings/" ) > - 1 ) ;
74
- include |= ( output . IndexOf ( "package/ProjectData~/Packages/" ) > - 1 ) ;
104
+ // only include these folders
105
+ var include = ( output . IndexOf ( "package/ProjectData~/Assets/" ) > - 1 ) ;
106
+ include |= ( output . IndexOf ( "package/ProjectData~/ProjectSettings/" ) > - 1 ) ;
107
+ include |= ( output . IndexOf ( "package/ProjectData~/Packages/" ) > - 1 ) ;
75
108
76
- // rename output path from "package/ProjectData~/Assets/" into "Assets/"
77
- output = output . Replace ( "package/ProjectData~/" , "" ) ;
109
+ // rename output path from "package/ProjectData~/Assets/" into "Assets/"
110
+ output = output . Replace ( "package/ProjectData~/" , "" ) ;
78
111
79
- if ( include == true && ! Directory . Exists ( Path . GetDirectoryName ( output ) ) ) Directory . CreateDirectory ( Path . GetDirectoryName ( output ) ) ;
112
+ if ( include == true && ! Directory . Exists ( Path . GetDirectoryName ( output ) ) ) Directory . CreateDirectory ( Path . GetDirectoryName ( output ) ) ;
80
113
81
- if ( ! name . Equals ( "./" , StringComparison . InvariantCulture ) )
82
- {
83
- if ( include == true )
114
+ // not folder
115
+ //if (name.Equals("./", StringComparison.InvariantCulture) == false)
116
+ if ( name . EndsWith ( "/" ) == false ) //Directories are zero size and don't need anything written
84
117
{
85
- //Console.WriteLine("output=" + output);
86
- using ( var str = File . Open ( output , FileMode . OpenOrCreate , FileAccess . Write ) )
118
+ if ( include == true )
119
+ {
120
+ //Console.WriteLine("output=" + output);
121
+ using ( var str = File . Open ( output , FileMode . OpenOrCreate , FileAccess . ReadWrite ) )
122
+ {
123
+ var buf = new byte [ size ] ;
124
+ stream . Read ( buf , 0 , buf . Length ) ;
125
+ // take only data from this folder
126
+ str . Write ( buf , 0 , buf . Length ) ;
127
+ }
128
+ }
129
+ else
87
130
{
88
131
var buf = new byte [ size ] ;
89
- pos += stream . Read ( buf , 0 , buf . Length ) ;
90
- // take only data from this folder
91
- str . Write ( buf , 0 , buf . Length ) ;
132
+ stream . Read ( buf , 0 , buf . Length ) ;
92
133
}
93
134
}
94
- else
95
- {
96
- //pos += size;
97
- var buf = new byte [ size ] ;
98
- pos += stream . Read ( buf , 0 , buf . Length ) ;
99
- //FakeSeekForward(stream, (int)size);
100
- }
101
135
}
102
136
103
- var offset = ( int ) ( 512 - ( pos % 512 ) ) ;
137
+ //Move head to next 512 byte block
138
+ var pos = stream . Position ;
139
+ var offset = 512 - ( pos % 512 ) ;
104
140
if ( offset == 512 ) offset = 0 ;
105
- FakeSeekForward ( stream , offset ) ;
106
- pos += offset ;
107
- }
108
- }
109
141
110
- private static void FakeSeekForward ( Stream stream , int offset )
111
- {
112
- if ( stream . CanSeek )
113
142
stream . Seek ( offset , SeekOrigin . Current ) ;
114
- else
115
- {
116
- int bytesRead = 0 ;
117
- var buffer = new byte [ offset ] ;
118
- while ( bytesRead < offset )
119
- {
120
- int read = stream . Read ( buffer , bytesRead , offset - bytesRead ) ;
121
- if ( read == 0 )
122
- throw new EndOfStreamException ( ) ;
123
- bytesRead += read ;
124
- }
125
143
}
126
144
}
127
- }
128
- }
145
+ } // class Tar
146
+ } // namespace TarLib
147
+
148
+
149
+ /*
150
+ This software is available under 2 licenses-- choose whichever you prefer.
151
+ ------------------------------------------------------------------------------
152
+ ALTERNATIVE A - MIT License
153
+ Copyright (c) 2017 Sean Barrett
154
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
155
+ this software and associated documentation files (the "Software"), to deal in
156
+ the Software without restriction, including without limitation the rights to
157
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
158
+ of the Software, and to permit persons to whom the Software is furnished to do
159
+ so, subject to the following conditions:
160
+ The above copyright notice and this permission notice shall be included in all
161
+ copies or substantial portions of the Software.
162
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
163
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
164
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
165
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
166
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
167
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
168
+ SOFTWARE.
169
+ ------------------------------------------------------------------------------
170
+ ALTERNATIVE B - Public Domain (www.unlicense.org)
171
+ This is free and unencumbered software released into the public domain.
172
+ Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
173
+ software, either in source code form or as a compiled binary, for any purpose,
174
+ commercial or non-commercial, and by any means.
175
+ In jurisdictions that recognize copyright laws, the author or authors of this
176
+ software dedicate any and all copyright interest in the software to the public
177
+ domain.We make this dedication for the benefit of the public at large and to
178
+ the detriment of our heirs and successors. We intend this dedication to be an
179
+ overt act of relinquishment in perpetuity of all present and future rights to
180
+ this software under copyright law.
181
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
182
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
184
+ AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
185
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
186
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
187
+ */
0 commit comments