go - How to be definite about the number of whitespace fmt.Fscanf consumes? -


i trying implement ppm decoder in go. ppm image format consists of plaintext header , binary image data. header looks (from spec):

each ppm image consists of following:

  1. a "magic number" identifying file type. ppm image's magic number 2 characters "p6".
  2. whitespace (blanks, tabs, crs, lfs).
  3. a width, formatted ascii characters in decimal.
  4. whitespace.
  5. a height, again in ascii decimal.
  6. whitespace.
  7. the maximum color value (maxval), again in ascii decimal. must less 65536 , more zero.
  8. a single whitespace character (usually newline).

i try decode header fmt.fscanf function. following call fmt.fscanf parses header (not addressing caveat explained below):

var magic string var width, height, maxval uint  fmt.fscanf(input,"%2s %d %d %d",&magic,&width,&height,&maxval) 

the documentation of fmt states:

note: fscan etc. can read 1 character (rune) past input return, means loop calling scan routine may skip of input. problem when there no space between input values. if reader provided fscan implements readrune, method used read characters. if reader implements unreadrune, method used save character , successive calls not lose data. attach readrune , unreadrune methods reader without capability, use bufio.newreader.

as next character after final whitespace beginning of image data, have how many whitespace fmt.fscanf did consume after reading maxval. code must work on whatever reader provided caller , parts of must not read past end of header, therefore wrapping stuff buffered reader not option; buffered reader might read more input want read.

some testing suggests parsing dummy character @ end solves issues:

var magic string var width, height, maxval uint var dummy byte  fmt.fscanf(input,"%2s %d %d %d%c",&magic,&width,&height,&maxval,&dummy) 

is guaranteed work according specification?

no, not consider safe. while works now, documentation states function reserves right read past value 1 character unless have unreadrune() method.

by wrapping reader in bufio.reader, can ensure reader has unreadrune() method. need read final whitespace yourself.

buf := bufio.newreader(input) fmt.fscanf(buf,"%2s %d %d %d",&magic,&width,&height,&maxval) buf.readrune() // remove next rune (the whitespace) buffer. 


edit:

as discussed in chat, can assume dummy char method works , write test know when stops working. test can like:

func testfmtbehavior(t *testing.t) {     // use multireader prevent r implementing io.runescanner     r := io.multireader(bytes.newreader([]byte("data  ")))      n, err := fmt.fscanf(r, "%s%c", new(string), new(byte))     if n != 2 || err != nil {         t.error("failed scan", n, err)     }      // dummy char read 1 char past "data".     // 1 byte should still remain     if n, err := r.read(make([]byte, 5)); n != 1 {         t.error("assertion failed", n, err)     } } 

Comments

Popular posts from this blog

monitor web browser programmatically in Android? -

Shrink a YouTube video to responsive width -

wpf - PdfWriter.GetInstance throws System.NullReferenceException -