...

Source file src/github.com/sassoftware/relic/lib/comdoc/stream.go

Documentation: github.com/sassoftware/relic/lib/comdoc

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package comdoc
    18  
    19  import (
    20  	"errors"
    21  	"io"
    22  )
    23  
    24  type streamReader struct {
    25  	remaining  uint32
    26  	nextSector SecID
    27  	sat        []SecID
    28  	sectorSize int
    29  	readSector func(SecID, []byte) error
    30  	buf, saved []byte
    31  }
    32  
    33  // Open a stream for reading
    34  func (r *ComDoc) ReadStream(e *DirEnt) (io.Reader, error) {
    35  	if e.Type != DirStream {
    36  		return nil, errors.New("not a stream")
    37  	}
    38  	sr := &streamReader{
    39  		remaining:  e.StreamSize,
    40  		nextSector: e.NextSector,
    41  	}
    42  	if e.StreamSize < r.Header.MinStdStreamSize {
    43  		sr.sectorSize = r.ShortSectorSize
    44  		sr.sat = r.SSAT
    45  		sr.readSector = r.readShortSector
    46  	} else {
    47  		sr.sectorSize = r.SectorSize
    48  		sr.sat = r.SAT
    49  		sr.readSector = r.readSector
    50  	}
    51  	sr.buf = make([]byte, sr.sectorSize)
    52  	return sr, nil
    53  }
    54  
    55  func (sr *streamReader) Read(d []byte) (copied int, err error) {
    56  	if sr.remaining == 0 {
    57  		return 0, io.EOF
    58  	} else if len(d) == 0 {
    59  		return 0, nil
    60  	}
    61  	if int64(len(d)) > int64(sr.remaining) {
    62  		d = d[:int(sr.remaining)]
    63  	}
    64  	// read from previously buffered sector
    65  	if len(sr.saved) > 0 {
    66  		n := len(sr.saved)
    67  		if n > len(d) {
    68  			n = len(d)
    69  		}
    70  		copy(d[:n], sr.saved[:n])
    71  		d = d[n:]
    72  		sr.saved = sr.saved[n:]
    73  		copied += n
    74  		sr.remaining -= uint32(n)
    75  	}
    76  	// read whole sectors
    77  	n := sr.sectorSize
    78  	for len(d) >= n {
    79  		if sr.nextSector < 0 {
    80  			return copied, errors.New("unexpected end to stream")
    81  		}
    82  		if err := sr.readSector(sr.nextSector, d[:n]); err != nil {
    83  			return copied, err
    84  		}
    85  		d = d[n:]
    86  		copied += n
    87  		sr.remaining -= uint32(n)
    88  		sr.nextSector = sr.sat[sr.nextSector]
    89  	}
    90  	// read partial sector and buffer the rest
    91  	if len(d) > 0 {
    92  		n = len(d)
    93  		if sr.nextSector < 0 {
    94  			return copied, errors.New("unexpected end to stream")
    95  		}
    96  		if err := sr.readSector(sr.nextSector, sr.buf); err != nil {
    97  			return copied, err
    98  		}
    99  		copy(d, sr.buf)
   100  		copied += n
   101  		sr.remaining -= uint32(n)
   102  		sr.saved = sr.buf[n:]
   103  		sr.nextSector = sr.sat[sr.nextSector]
   104  	}
   105  	return copied, nil
   106  }
   107  
   108  // Store a blob as a chain of sectors, updating the sector table (or
   109  // short-sector table if "short" is set)  and return the first sector ID
   110  func (r *ComDoc) addStream(contents []byte, short bool) (SecID, error) {
   111  	var sectorSize int
   112  	var sat, freeList []SecID
   113  	if short {
   114  		sectorSize = int(r.ShortSectorSize)
   115  		needSectors := (len(contents) + sectorSize - 1) / sectorSize
   116  		freeList = r.makeFreeSectors(needSectors, true)
   117  		sat = r.SSAT
   118  	} else {
   119  		sectorSize = int(r.SectorSize)
   120  		needSectors := (len(contents) + sectorSize - 1) / sectorSize
   121  		freeList = r.makeFreeSectors(needSectors, false)
   122  		sat = r.SAT
   123  	}
   124  	first := SecIDEndOfChain
   125  	previous := first
   126  	for _, i := range freeList {
   127  		if previous == SecIDEndOfChain {
   128  			first = i
   129  		} else {
   130  			sat[previous] = i
   131  		}
   132  		previous = i
   133  		// write to file
   134  		n := sectorSize
   135  		if n > len(contents) {
   136  			n = len(contents)
   137  		}
   138  		var err error
   139  		if short {
   140  			err = r.writeShortSector(i, contents[:n])
   141  		} else {
   142  			err = r.writeSector(i, contents[:n])
   143  		}
   144  		if err != nil {
   145  			return 0, err
   146  		}
   147  		contents = contents[n:]
   148  	}
   149  	sat[previous] = SecIDEndOfChain
   150  	if len(contents) > 0 {
   151  		panic("didn't allocate enough sectors")
   152  	}
   153  	return first, nil
   154  }
   155  

View as plain text