package vfs

import (
	
	
	_ 
	

	

	
	
)

func cksmWrapFile( File,  OpenFlag) File {
	// Checksum only main databases.
	if &OPEN_MAIN_DB == 0 {
		return 
	}
	return &cksmFile{File: }
}

type cksmFile struct {
	File
	verifyCksm  bool
	computeCksm bool
}

func ( *cksmFile) ( []byte,  int64) ( int,  error) {
	,  = .File.ReadAt(, )
	 = [:]

	if isHeader(, ) {
		.init((*[100]byte)())
	}

	// Verify checksums.
	if .verifyCksm && sql3util.ValidPageSize(len()) {
		 := cksmCompute([:len()-8])
		 := *(*[8]byte)([len()-8:])
		if  !=  {
			return 0, _IOERR_DATA
		}
	}
	return , 
}

func ( *cksmFile) ( []byte,  int64) ( int,  error) {
	if isHeader(, ) {
		.init((*[100]byte)())
	}

	// Compute checksums.
	if .computeCksm && sql3util.ValidPageSize(len()) {
		*(*[8]byte)([len()-8:]) = cksmCompute([:len()-8])
	}

	return .File.WriteAt(, )
}

func ( *cksmFile) ( string,  string) (string, error) {
	switch  {
	case "checksum_verification":
		,  := sql3util.ParseBool()
		if  {
			.verifyCksm =  && .computeCksm
		}
		if !.verifyCksm {
			return "0", nil
		}
		return "1", nil

	case "page_size":
		if .computeCksm &&  != "" {
			// Do not allow page size changes on a checksum database.
			return "", nil
		}
	}
	return "", _NOTFOUND
}

func ( *cksmFile) () DeviceCharacteristic {
	 := .File.DeviceCharacteristics()
	if .verifyCksm {
		 &^= IOCAP_SUBPAGE_READ
	}
	return 
}

func ( *cksmFile) ( context.Context,  api.Module,  _FcntlOpcode,  ptr_t) _ErrorCode {
	if  == _FCNTL_PRAGMA {
		 := vfsFileControlImpl(, , , , )
		if  != _NOTFOUND {
			return 
		}
	}
	return vfsFileControlImpl(, , .File, , )
}

func ( *cksmFile) ( *[100]byte) {
	if  := [20] == 8;  != .computeCksm {
		.computeCksm = 
		.verifyCksm = 
	}
}

func ( *cksmFile) () SharedMemory {
	if ,  := .File.(FileSharedMemory);  {
		return .SharedMemory()
	}
	return nil
}

func ( *cksmFile) () File {
	return .File
}

func isHeader( []byte,  int64) bool {
	return  == 0 && len() >= 100 && bytes.HasPrefix(, []byte("SQLite format 3\000"))
}

func cksmCompute( []byte) ( [8]byte) {
	var ,  uint32
	for len() >= 8 {
		 += binary.LittleEndian.Uint32([0:4]) + 
		 += binary.LittleEndian.Uint32([4:8]) + 
		 = [8:]
	}
	if len() != 0 {
		panic(util.AssertErr())
	}
	binary.LittleEndian.PutUint32([0:4], )
	binary.LittleEndian.PutUint32([4:8], )
	return
}