ClassiCube/ClassicalSharp/Network/Utils/GZipHeaderReader.cs
2016-05-09 23:35:44 +10:00

124 lines
3.0 KiB
C#

// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.IO;
namespace ClassicalSharp.Network {
internal class GZipHeaderReader {
enum State {
Header1, Header2, CompressionMethod, Flags,
LastModifiedTime, CompressionFlags, OperatingSystem,
HeaderChecksum, Filename, Comment, Done,
}
State state = State.Header1;
public bool done;
int flags;
int partsRead;
public bool ReadHeader( Stream s ) {
switch( state ) {
case State.Header1:
if( !ReadAndCheckHeaderByte( s, 0x1F ) )
return false;
goto case State.Header2;
case State.Header2:
if( !ReadAndCheckHeaderByte( s, 0x8B ) )
return false;
goto case State.CompressionMethod;
case State.CompressionMethod:
if( !ReadAndCheckHeaderByte( s, 0x08 ) )
return false;
goto case State.Flags;
case State.Flags:
if( !ReadHeaderByte( s, out flags ) )
return false;
if( (flags & 0x04) != 0 )
throw new NotSupportedException( "Unsupported gzip flags: " + flags );
goto case State.LastModifiedTime;
case State.LastModifiedTime:
for( ; partsRead < 4; partsRead++ ) {
int part = s.ReadByte();
if( part == -1 )
return false;
}
partsRead = 0;
state = State.CompressionFlags;
goto case State.CompressionFlags;
case State.CompressionFlags:
int comFlags;
if( !ReadHeaderByte( s, out comFlags ) )
return false;
goto case State.OperatingSystem;
case State.OperatingSystem:
int os;
if( !ReadHeaderByte( s, out os ) )
return false;
goto case State.Filename;
case State.Filename:
if( (flags & 0x08) != 0 ) {
for( ; ; ) {
int part = s.ReadByte();
if( part == -1 ) return false;
if( part == 0 ) break;
}
}
state = State.Comment;
goto case State.Comment;
case State.Comment:
if( (flags & 0x10) != 0 ) {
for( ; ; ) {
int part = s.ReadByte();
if( part == -1 ) return false;
if( part == 0 ) break;
}
}
state = State.HeaderChecksum;
goto case State.HeaderChecksum;
case State.HeaderChecksum:
if( ( flags & 0x02 ) != 0 ) {
for( ; partsRead < 2; partsRead++ ) {
int part = s.ReadByte();
if( part == -1 )
return false;
}
}
partsRead = 0;
state = State.Done;
done = true;
return true;
}
return true;
}
bool ReadAndCheckHeaderByte( Stream s, byte expected ) {
int value;
if( !ReadHeaderByte( s, out value ) )
return false;
if( value != expected )
throw new InvalidDataException( "Unepxected constant in GZip header. (" + expected + "-" + value + ")" );
return true;
}
bool ReadHeaderByte( Stream s, out int value ) {
value = s.ReadByte();
if( value == -1 )
return false;
state++;
return true;
}
}
}