// Copyright 2011 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 webp

import (
	
	
	
	
	
	

	
	
	
)

var errInvalidFormat = errors.New("webp: invalid format")

var (
	fccALPH = riff.FourCC{'A', 'L', 'P', 'H'}
	fccVP8  = riff.FourCC{'V', 'P', '8', ' '}
	fccVP8L = riff.FourCC{'V', 'P', '8', 'L'}
	fccVP8X = riff.FourCC{'V', 'P', '8', 'X'}
	fccWEBP = riff.FourCC{'W', 'E', 'B', 'P'}
)

func decode( io.Reader,  bool) (image.Image, image.Config, error) {
	, ,  := riff.NewReader()
	if  != nil {
		return nil, image.Config{}, 
	}
	if  != fccWEBP {
		return nil, image.Config{}, errInvalidFormat
	}

	var (
		          []byte
		    int
		      bool
		       bool
		  uint32
		 uint32
		            [10]byte
	)
	for {
		, , ,  := .Next()
		if  == io.EOF {
			 = errInvalidFormat
		}
		if  != nil {
			return nil, image.Config{}, 
		}

		switch  {
		case fccALPH:
			if ! {
				return nil, image.Config{}, errInvalidFormat
			}
			 = false
			// Read the Pre-processing | Filter | Compression byte.
			if ,  := io.ReadFull(, [:1]);  != nil {
				if  == io.EOF {
					 = errInvalidFormat
				}
				return nil, image.Config{}, 
			}
			, ,  = readAlpha(, , , [0]&0x03)
			if  != nil {
				return nil, image.Config{}, 
			}
			unfilterAlpha(, , ([0]>>2)&0x03)

		case fccVP8:
			if  || int32() < 0 {
				return nil, image.Config{}, errInvalidFormat
			}
			 := vp8.NewDecoder()
			.Init(, int())
			,  := .DecodeFrameHeader()
			if  != nil {
				return nil, image.Config{}, 
			}
			if  && (.Width != int()+1 || .Height != int()+1) {
				return nil, image.Config{}, errInvalidFormat
			}
			if  {
				return nil, image.Config{
					ColorModel: color.YCbCrModel,
					Width:      .Width,
					Height:     .Height,
				}, nil
			}
			,  := .DecodeFrame()
			if  != nil {
				return nil, image.Config{}, 
			}
			if  != nil {
				return &image.NYCbCrA{
					YCbCr:   *,
					A:       ,
					AStride: ,
				}, image.Config{}, nil
			}
			return , image.Config{}, nil

		case fccVP8L:
			if  != nil {
				return nil, image.Config{}, errInvalidFormat
			}
			if  {
				,  := vp8l.DecodeConfig()
				return nil, , 
			}
			if  {
				// Verify the VP8L chunk dimensions match before
				// calling vp8l.Decode, to catch malicious images
				// following a small VP8X header with a huge VP8L chunk.
				//
				// Peek the VP8L header.
				//
				// chunkData is always an unbuffered riff.chunkReader.
				// Creating a bufio.Reader here doesn't add any
				// inefficiency, since the vp8l package will do it
				// if we don't.
				 := bufio.NewReader()
				 = 
				const  = 5
				,  := .Peek()
				if  != nil {
					if  == io.EOF {
						 = errInvalidFormat
					}
					return nil, image.Config{}, 
				}
				,  := vp8l.DecodeConfig(bytes.NewReader())
				if  != nil {
					return nil, image.Config{}, 
				}
				if .Width != int()+1 || .Height != int()+1 {
					return nil, image.Config{}, errInvalidFormat
				}
			}
			,  := vp8l.Decode()
			if  != nil {
				return nil, image.Config{}, 
			}
			return , image.Config{}, nil

		case fccVP8X:
			if  {
				return nil, image.Config{}, errInvalidFormat
			}
			 = true
			if  != 10 {
				return nil, image.Config{}, errInvalidFormat
			}
			if ,  := io.ReadFull(, [:10]);  != nil {
				return nil, image.Config{}, 
			}
			const (
				    = 1 << 1
				  = 1 << 2
				 = 1 << 3
				        = 1 << 4
				   = 1 << 5
			)
			 = ([0] & ) != 0
			 = uint32([4]) | uint32([5])<<8 | uint32([6])<<16
			 = uint32([7]) | uint32([8])<<8 | uint32([9])<<16
			 := uint64() + 1
			 := uint64() + 1
			if * > 1<<31-1 {
				// The product of _Canvas Width_ and _Canvas Height_ MUST be
				// at most 2^32 - 1.
				// But it also needs to fit in an int, so limit it to MaxInt32.
				return nil, image.Config{}, errInvalidFormat
			}
			if  {
				if  {
					return nil, image.Config{
						ColorModel: color.NYCbCrAModel,
						Width:      int() + 1,
						Height:     int() + 1,
					}, nil
				}
				return nil, image.Config{
					ColorModel: color.YCbCrModel,
					Width:      int() + 1,
					Height:     int() + 1,
				}, nil
			}
		}
	}
}

func readAlpha( io.Reader, ,  uint32,  byte) (
	 []byte,  int,  error) {

	switch  {
	case 0:
		 := int() + 1
		 := int() + 1
		 = make([]byte, *)
		if ,  := io.ReadFull(, );  != nil {
			return nil, 0, 
		}
		return , , nil

	case 1:
		// Read the VP8L-compressed alpha values. First, synthesize a 5-byte VP8L header:
		// a 1-byte magic number, a 14-bit widthMinusOne, a 14-bit heightMinusOne,
		// a 1-bit (ignored, zero) alphaIsUsed and a 3-bit (zero) version.
		// TODO(nigeltao): be more efficient than decoding an *image.NRGBA just to
		// extract the green values to a separately allocated []byte. Fixing this
		// will require changes to the vp8l package's API.
		if  > 0x3fff ||  > 0x3fff {
			return nil, 0, errors.New("webp: invalid format")
		}
		,  := vp8l.Decode(io.MultiReader(
			bytes.NewReader([]byte{
				0x2f, // VP8L magic number.
				uint8(),
				uint8(>>8) | uint8(<<6),
				uint8( >> 2),
				uint8( >> 10),
			}),
			,
		))
		if  != nil {
			return nil, 0, 
		}
		// The green values of the inner NRGBA image are the alpha values of the
		// outer NYCbCrA image.
		 := .(*image.NRGBA).Pix
		 = make([]byte, len()/4)
		for  := range  {
			[] = [4*+1]
		}
		return , int() + 1, nil
	}
	return nil, 0, errInvalidFormat
}

func unfilterAlpha( []byte,  int,  byte) {
	if len() == 0 ||  == 0 {
		return
	}
	switch  {
	case 1: // Horizontal filter.
		for  := 1;  < ; ++ {
			[] += [-1]
		}
		for  := ;  < len();  +=  {
			// The first column is equivalent to the vertical filter.
			[] += [-]

			for  := 1;  < ; ++ {
				[+] += [+-1]
			}
		}

	case 2: // Vertical filter.
		// The first row is equivalent to the horizontal filter.
		for  := 1;  < ; ++ {
			[] += [-1]
		}

		for  := ;  < len(); ++ {
			[] += [-]
		}

	case 3: // Gradient filter.
		// The first row is equivalent to the horizontal filter.
		for  := 1;  < ; ++ {
			[] += [-1]
		}

		for  := ;  < len();  +=  {
			// The first column is equivalent to the vertical filter.
			[] += [-]

			// The interior is predicted on the three top/left pixels.
			for  := 1;  < ; ++ {
				 := int([+--1])
				 := int([+-])
				 := int([+-1])
				 :=  +  - 
				if  < 0 {
					 = 0
				} else if  > 255 {
					 = 255
				}
				[+] += uint8()
			}
		}
	}
}

// Decode reads a WEBP image from r and returns it as an image.Image.
func ( io.Reader) (image.Image, error) {
	, ,  := decode(, false)
	if  != nil {
		return nil, 
	}
	return , nil
}

// DecodeConfig returns the color model and dimensions of a WEBP image without
// decoding the entire image.
func ( io.Reader) (image.Config, error) {
	, ,  := decode(, true)
	return , 
}

func init() {
	image.RegisterFormat("webp", "RIFF????WEBPVP8", Decode, DecodeConfig)
}