package smb2

var zero [16]byte

// ----------------------------------------------------------------------------
// SMB2 FILEID
//

type FileId struct {
	Persistent [8]byte
	Volatile   [8]byte
}

func ( *FileId) () bool {
	if  == nil {
		return true
	}

	for ,  := range .Persistent[:] {
		if  != 0 {
			return false
		}
	}
	for ,  := range .Volatile[:] {
		if  != 0 {
			return false
		}
	}
	return true
}

func ( *FileId) () int {
	return 16
}

func ( *FileId) ( []byte) {
	if  == nil {
		copy([:16], zero[:])
	} else {
		copy([:8], .Persistent[:])
		copy([8:16], .Volatile[:])
	}
}

type FileIdDecoder []byte

func ( FileIdDecoder) () []byte {
	return [:8]
}

func ( FileIdDecoder) () []byte {
	return [8:16]
}

func ( FileIdDecoder) () *FileId {
	var  FileId
	copy(.Persistent[:], [:8])
	copy(.Volatile[:], [8:16])
	return &
}

// ----------------------------------------------------------------------------
// SMB2 NEGOTIATE Contexts
//

// From SMB311

type HashContext struct {
	HashAlgorithms []uint16
	HashSalt       []byte
}

func ( *HashContext) () int {
	return 8 + 4 + len(.HashAlgorithms)*2 + len(.HashSalt)
}

func ( *HashContext) ( []byte) {
	le.PutUint16([:2], SMB2_PREAUTH_INTEGRITY_CAPABILITIES)                // ContextType
	le.PutUint16([2:4], uint16(4+len(.HashAlgorithms)*2+len(.HashSalt))) // DataLength

	{
		 := NegotiateContextDecoder().Data()

		// HashAlgorithms
		{
			 := [4:]
			for ,  := range .HashAlgorithms {
				le.PutUint16([2*:2*+2], )
			}
			le.PutUint16([:2], uint16(len(.HashAlgorithms)))
		}

		// HashSalt
		{
			 := 4 + len(.HashAlgorithms)*2
			copy([:], .HashSalt)
			le.PutUint16([2:4], uint16(len(.HashSalt)))
		}
	}
}

type CipherContext struct {
	Ciphers []uint16
}

func ( *CipherContext) () int {
	return 8 + 2 + len(.Ciphers)*2
}

func ( *CipherContext) ( []byte) {
	le.PutUint16([:2], SMB2_ENCRYPTION_CAPABILITIES) // ContextType
	le.PutUint16([2:4], uint16(2+len(.Ciphers)*2))  // DataLength

	{
		 := NegotiateContextDecoder().Data()

		{ // Ciphers
			 := [2:]
			for ,  := range .Ciphers {
				le.PutUint16([2*:2*+2], )
			}
			le.PutUint16([:2], uint16(len(.Ciphers))) // CipherCount
		}
	}
}

// From SMB311

type NegotiateContextDecoder []byte

func ( NegotiateContextDecoder) () bool {
	if len() < 8 {
		return true
	}

	if len() < 8+int(.DataLength()) {
		return true
	}

	return false
}

func ( NegotiateContextDecoder) () uint16 {
	return le.Uint16([:2])
}

func ( NegotiateContextDecoder) () uint16 {
	return le.Uint16([2:4])
}

func ( NegotiateContextDecoder) () []byte {
	 := .DataLength()
	return [8 : 8+]
}

func ( NegotiateContextDecoder) () int {
	return Roundup(8+int(.DataLength()), 8)
}

// From SMB311

type HashContextDataDecoder []byte

func ( HashContextDataDecoder) () bool {
	if len() < 4 {
		return true
	}

	if len() < 4+int(.HashAlgorithmCount())*2+int(.SaltLength()) {
		return true
	}

	return false
}

func ( HashContextDataDecoder) () uint16 {
	return le.Uint16([:2])
}

func ( HashContextDataDecoder) () uint16 {
	return le.Uint16([2:4])
}

func ( HashContextDataDecoder) () []uint16 {
	 := [4:]
	 := make([]uint16, .HashAlgorithmCount())
	for  := range  {
		[] = le.Uint16([2* : 2*+2])
	}
	return 
}

func ( HashContextDataDecoder) () []byte {
	 := 4 + .HashAlgorithmCount()*2
	 := .SaltLength()
	return [ : +]
}

type CipherContextDataDecoder []byte

func ( CipherContextDataDecoder) () bool {
	if len() < 2 {
		return true
	}

	if len() < 2+int(.CipherCount())*2 {
		return true
	}

	return false
}

func ( CipherContextDataDecoder) () uint16 {
	return le.Uint16([:2])
}

func ( CipherContextDataDecoder) () []uint16 {
	 := [2:]
	 := make([]uint16, .CipherCount())
	for  := range  {
		[] = le.Uint16([2* : 2*+2])
	}
	return 
}

type QueryQuotaInfo struct {
	ReturnSingle bool
	RestartScan  bool
	Sids         []Sid
}

func ( *QueryQuotaInfo) () int {
	if len(.Sids) == 0 {
		return 16
	}
	if len(.Sids) == 1 {
		return 16 + .Sids[0].Size()
	}
	 := 16
	for ,  := range .Sids {
		 += 8 + .Size()
	}
	return 
}

func ( *QueryQuotaInfo) ( []byte) {
	if .ReturnSingle {
		[0] = 1
	}
	if .RestartScan {
		[1] = 1
	}
	if len(.Sids) > 0 {
		if len(.Sids) == 1 {
			 := .Sids[0]
			.Encode([16:])
			le.PutUint32([8:12], uint32(.Size()))
			le.PutUint32([12:16], 0)
		} else {
			le.PutUint32([4:8], 1)
			 := 16
			for ,  := range .Sids {
				 := .Size()
				.Encode([+8:])
				le.PutUint32([:+4], uint32(+))
				le.PutUint32([+4:+8], uint32())
				 += 8 + 
			}
		}
	}
}