// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package asn1

import (
	
	
	
	
	
	
	
	
)

// A forkableWriter is an in-memory buffer that can be
// 'forked' to create new forkableWriters that bracket the
// original. After
//    pre, post := w.fork()
// the overall sequence of bytes represented is logically w+pre+post.
type forkableWriter struct {
	*bytes.Buffer
	pre, post *forkableWriter
}

func newForkableWriter() *forkableWriter {
	return &forkableWriter{new(bytes.Buffer), nil, nil}
}

func ( *forkableWriter) () (,  *forkableWriter) {
	if .pre != nil || .post != nil {
		panic("have already forked")
	}
	.pre = newForkableWriter()
	.post = newForkableWriter()
	return .pre, .post
}

func ( *forkableWriter) () ( int) {
	 += .Buffer.Len()
	if .pre != nil {
		 += .pre.()
	}
	if .post != nil {
		 += .post.()
	}
	return
}

func ( *forkableWriter) ( io.Writer) ( int,  error) {
	,  = .Write(.Bytes())
	if  != nil {
		return
	}

	var  int

	if .pre != nil {
		,  = .pre.()
		 += 
		if  != nil {
			return
		}
	}

	if .post != nil {
		,  = .post.()
		 += 
	}
	return
}

func marshalBase128Int( *forkableWriter,  int64) ( error) {
	if  == 0 {
		 = .WriteByte(0)
		return
	}

	 := 0
	for  := ;  > 0;  >>= 7 {
		++
	}

	for  :=  - 1;  >= 0; -- {
		 := byte( >> uint(*7))
		 &= 0x7f
		if  != 0 {
			 |= 0x80
		}
		 = .WriteByte()
		if  != nil {
			return
		}
	}

	return nil
}

func marshalInt64( *forkableWriter,  int64) ( error) {
	 := int64Length()

	for ;  > 0; -- {
		 = .WriteByte(byte( >> uint((-1)*8)))
		if  != nil {
			return
		}
	}

	return nil
}

func int64Length( int64) ( int) {
	 = 1

	for  > 127 {
		++
		 >>= 8
	}

	for  < -128 {
		++
		 >>= 8
	}

	return
}

func marshalBigInt( *forkableWriter,  *big.Int) ( error) {
	if .Sign() < 0 {
		// A negative number has to be converted to two's-complement
		// form. So we'll subtract 1 and invert. If the
		// most-significant-bit isn't set then we'll need to pad the
		// beginning with 0xff in order to keep the number negative.
		 := new(big.Int).Neg()
		.Sub(, bigOne)
		 := .Bytes()
		for  := range  {
			[] ^= 0xff
		}
		if len() == 0 || [0]&0x80 == 0 {
			 = .WriteByte(0xff)
			if  != nil {
				return
			}
		}
		_,  = .Write()
	} else if .Sign() == 0 {
		// Zero is written as a single 0 zero rather than no bytes.
		 = .WriteByte(0x00)
	} else {
		 := .Bytes()
		if len() > 0 && [0]&0x80 != 0 {
			// We'll have to pad this with 0x00 in order to stop it
			// looking like a negative number.
			 = .WriteByte(0)
			if  != nil {
				return
			}
		}
		_,  = .Write()
	}
	return
}

func marshalLength( *forkableWriter,  int) ( error) {
	 := lengthLength()

	for ;  > 0; -- {
		 = .WriteByte(byte( >> uint((-1)*8)))
		if  != nil {
			return
		}
	}

	return nil
}

func lengthLength( int) ( int) {
	 = 1
	for  > 255 {
		++
		 >>= 8
	}
	return
}

func marshalTagAndLength( *forkableWriter,  tagAndLength) ( error) {
	 := uint8(.class) << 6
	if .isCompound {
		 |= 0x20
	}
	if .tag >= 31 {
		 |= 0x1f
		 = .WriteByte()
		if  != nil {
			return
		}
		 = marshalBase128Int(, int64(.tag))
		if  != nil {
			return
		}
	} else {
		 |= uint8(.tag)
		 = .WriteByte()
		if  != nil {
			return
		}
	}

	if .length >= 128 {
		 := lengthLength(.length)
		 = .WriteByte(0x80 | byte())
		if  != nil {
			return
		}
		 = marshalLength(, .length)
		if  != nil {
			return
		}
	} else {
		 = .WriteByte(byte(.length))
		if  != nil {
			return
		}
	}

	return nil
}

func marshalBitString( *forkableWriter,  BitString) ( error) {
	 := byte((8 - .BitLength%8) % 8)
	 = .WriteByte()
	if  != nil {
		return
	}
	_,  = .Write(.Bytes)
	return
}

func marshalObjectIdentifier( *forkableWriter,  []int) ( error) {
	if len() < 2 || [0] > 2 || ([0] < 2 && [1] >= 40) {
		return StructuralError{"invalid object identifier"}
	}

	 = marshalBase128Int(, int64([0]*40+[1]))
	if  != nil {
		return
	}
	for  := 2;  < len(); ++ {
		 = marshalBase128Int(, int64([]))
		if  != nil {
			return
		}
	}

	return
}

func marshalPrintableString( *forkableWriter,  string) ( error) {
	 := []byte()
	for ,  := range  {
		if !isPrintable() {
			return StructuralError{"PrintableString contains invalid character"}
		}
	}

	_,  = .Write()
	return
}

func marshalIA5String( *forkableWriter,  string) ( error) {
	 := []byte()
	for ,  := range  {
		if  > 127 {
			return StructuralError{"IA5String contains invalid character"}
		}
	}

	_,  = .Write()
	return
}

func marshalUTF8String( *forkableWriter,  string) ( error) {
	_,  = .Write([]byte())
	return
}

func marshalTwoDigits( *forkableWriter,  int) ( error) {
	 = .WriteByte(byte('0' + (/10)%10))
	if  != nil {
		return
	}
	return .WriteByte(byte('0' + %10))
}

func marshalFourDigits( *forkableWriter,  int) ( error) {
	var  [4]byte
	for  := range  {
		[3-] = '0' + byte(%10)
		 /= 10
	}
	_,  = .Write([:])
	return
}

func outsideUTCRange( time.Time) bool {
	 := .Year()
	return  < 1950 ||  >= 2050
}

func marshalUTCTime( *forkableWriter,  time.Time) ( error) {
	 := .Year()

	switch {
	case 1950 <=  &&  < 2000:
		 = marshalTwoDigits(, -1900)
	case 2000 <=  &&  < 2050:
		 = marshalTwoDigits(, -2000)
	default:
		return StructuralError{"cannot represent time as UTCTime"}
	}
	if  != nil {
		return
	}

	return marshalTimeCommon(, )
}

func marshalGeneralizedTime( *forkableWriter,  time.Time) ( error) {
	 := .Year()
	if  < 0 ||  > 9999 {
		return StructuralError{"cannot represent time as GeneralizedTime"}
	}
	if  = marshalFourDigits(, );  != nil {
		return
	}

	return marshalTimeCommon(, )
}

func marshalTimeCommon( *forkableWriter,  time.Time) ( error) {
	, ,  := .Date()

	 = marshalTwoDigits(, int())
	if  != nil {
		return
	}

	 = marshalTwoDigits(, )
	if  != nil {
		return
	}

	, ,  := .Clock()

	 = marshalTwoDigits(, )
	if  != nil {
		return
	}

	 = marshalTwoDigits(, )
	if  != nil {
		return
	}

	 = marshalTwoDigits(, )
	if  != nil {
		return
	}

	,  := .Zone()

	switch {
	case /60 == 0:
		 = .WriteByte('Z')
		return
	case  > 0:
		 = .WriteByte('+')
	case  < 0:
		 = .WriteByte('-')
	}

	if  != nil {
		return
	}

	 :=  / 60
	if  < 0 {
		 = -
	}

	 = marshalTwoDigits(, /60)
	if  != nil {
		return
	}

	 = marshalTwoDigits(, %60)
	return
}

func stripTagAndLength( []byte) []byte {
	, ,  := parseTagAndLength(, 0)
	if  != nil {
		return 
	}
	return [:]
}

func marshalBody( *forkableWriter,  reflect.Value,  fieldParameters) ( error) {
	switch .Type() {
	case flagType:
		return nil
	case timeType:
		 := .Interface().(time.Time)
		if .timeType == TagGeneralizedTime || outsideUTCRange() {
			return marshalGeneralizedTime(, )
		} else {
			return marshalUTCTime(, )
		}
	case bitStringType:
		return marshalBitString(, .Interface().(BitString))
	case objectIdentifierType:
		return marshalObjectIdentifier(, .Interface().(ObjectIdentifier))
	case bigIntType:
		return marshalBigInt(, .Interface().(*big.Int))
	}

	switch  := ; .Kind() {
	case reflect.Bool:
		if .Bool() {
			return .WriteByte(255)
		} else {
			return .WriteByte(0)
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return marshalInt64(, .Int())
	case reflect.Struct:
		 := .Type()

		 := 0

		// If the first element of the structure is a non-empty
		// RawContents, then we don't bother serializing the rest.
		if .NumField() > 0 && .Field(0).Type == rawContentsType {
			 := .Field(0)
			if .Len() > 0 {
				 := make([]byte, .Len())
				for  := 0;  < .Len(); ++ {
					[] = uint8(.Index().Uint())
				}
				/* The RawContents will contain the tag and
				 * length fields but we'll also be writing
				 * those ourselves, so we strip them out of
				 * bytes */
				_,  = .Write(stripTagAndLength())
				return
			} else {
				 = 1
			}
		}

		for  := ;  < .NumField(); ++ {
			var  *forkableWriter
			,  = .fork()
			 = marshalField(, .Field(), parseFieldParameters(.Field().Tag.Get("asn1")))
			if  != nil {
				return
			}
		}
		return
	case reflect.Slice:
		 := .Type()
		if .Elem().Kind() == reflect.Uint8 {
			 := make([]byte, .Len())
			for  := 0;  < .Len(); ++ {
				[] = uint8(.Index().Uint())
			}
			_,  = .Write()
			return
		}

		// jtasn1 Pass on the tags to the members but need to unset explicit switch and implicit value
		//var fp fieldParameters
		.explicit = false
		.tag = nil
		for  := 0;  < .Len(); ++ {
			var  *forkableWriter
			,  = .fork()
			 = marshalField(, .Index(), )
			if  != nil {
				return
			}
		}
		return
	case reflect.String:
		switch .stringType {
		case TagIA5String:
			return marshalIA5String(, .String())
		case TagPrintableString:
			return marshalPrintableString(, .String())
		default:
			return marshalUTF8String(, .String())
		}
	}

	return StructuralError{"unknown Go type"}
}

func marshalField( *forkableWriter,  reflect.Value,  fieldParameters) ( error) {
	if !.IsValid() {
		return fmt.Errorf("asn1: cannot marshal nil value")
	}
	// If the field is an interface{} then recurse into it.
	if .Kind() == reflect.Interface && .Type().NumMethod() == 0 {
		return (, .Elem(), )
	}

	if .Kind() == reflect.Slice && .Len() == 0 && .omitEmpty {
		return
	}

	if .optional && .defaultValue != nil && canHaveDefaultValue(.Kind()) {
		 := reflect.New(.Type()).Elem()
		.SetInt(*.defaultValue)

		if reflect.DeepEqual(.Interface(), .Interface()) {
			return
		}
	}

	// If no default value is given then the zero value for the type is
	// assumed to be the default value. This isn't obviously the correct
	// behaviour, but it's what Go has traditionally done.
	if .optional && .defaultValue == nil {
		if reflect.DeepEqual(.Interface(), reflect.Zero(.Type()).Interface()) {
			return
		}
	}

	if .Type() == rawValueType {
		 := .Interface().(RawValue)
		if len(.FullBytes) != 0 {
			_,  = .Write(.FullBytes)
		} else {
			 = marshalTagAndLength(, tagAndLength{.Class, .Tag, len(.Bytes), .IsCompound})
			if  != nil {
				return
			}
			_,  = .Write(.Bytes)
		}
		return
	}

	, ,  := getUniversalType(.Type())
	if ! {
		 = StructuralError{fmt.Sprintf("unknown Go type: %v", .Type())}
		return
	}
	 := ClassUniversal

	if .timeType != 0 &&  != TagUTCTime {
		return StructuralError{"explicit time type given to non-time member"}
	}

	// jtasn1 updated to allow slices of strings
	if .stringType != 0 && !( == TagPrintableString || (.Kind() == reflect.Slice &&  == 16 && .Type().Elem().Kind() == reflect.String)) {
		return StructuralError{"explicit string type given to non-string member"}
	}

	switch  {
	case TagPrintableString:
		if .stringType == 0 {
			// This is a string without an explicit string type. We'll use
			// a PrintableString if the character set in the string is
			// sufficiently limited, otherwise we'll use a UTF8String.
			for ,  := range .String() {
				if  >= utf8.RuneSelf || !isPrintable(byte()) {
					if !utf8.ValidString(.String()) {
						return errors.New("asn1: string not valid UTF-8")
					}
					 = TagUTF8String
					break
				}
			}
		} else {
			 = .stringType
		}
	case TagUTCTime:
		if .timeType == TagGeneralizedTime || outsideUTCRange(.Interface().(time.Time)) {
			 = TagGeneralizedTime
		}
	}

	if .set {
		if  != TagSequence {
			return StructuralError{"non sequence tagged as set"}
		}
		 = TagSet
	}

	,  := .fork()

	 = marshalBody(, , )
	if  != nil {
		return
	}

	 := .Len()

	var  *forkableWriter
	if .explicit {
		,  = .fork()
	}

	if !.explicit && .tag != nil {
		// implicit tag.
		 = *.tag
		 = ClassContextSpecific
	}

	 = marshalTagAndLength(, tagAndLength{, , , })
	if  != nil {
		return
	}

	if .explicit {
		 = marshalTagAndLength(, tagAndLength{
			class:      ClassContextSpecific,
			tag:        *.tag,
			length:      + .Len(),
			isCompound: true,
		})
	}

	return 
}

// Marshal returns the ASN.1 encoding of val.
//
// In addition to the struct tags recognised by Unmarshal, the following can be
// used:
//
//	ia5:		causes strings to be marshaled as ASN.1, IA5 strings
//	omitempty:	causes empty slices to be skipped
//	printable:	causes strings to be marshaled as ASN.1, PrintableString strings.
//	utf8:		causes strings to be marshaled as ASN.1, UTF8 strings
func ( interface{}) ([]byte, error) {
	var  bytes.Buffer
	 := reflect.ValueOf()
	 := newForkableWriter()
	 := marshalField(, , fieldParameters{})
	if  != nil {
		return nil, 
	}
	_,  = .writeTo(&)
	return .Bytes(), 
}