2

I have to read a PPM file with its data encrypted (metadata is not encrypted), using Go, and the file format is given to me containing:

  • The "P3" magic number (read as string)

  • Image width (read as integer)

  • Image height (read as integer)

  • Maximum color value (read as integer)

Then, I need to read the rest of the file is the encrypted bits, which I have to read as a single byte array/slice.

e.g.:

P6 480 360 255 �š��GHFHFI�GHFHFG~EG~EG~E ... HFD{BR�Rz�y|�vxyyhlf%8&NFzx 

What is a good way to read string and integers (the 4 initial metadata values) and the rest (encrypted part) as bytes from the file? It can be the most efficient, but the cleanest (less lines) is preferred.

3
  • Are the integers in a string representation, or are they binary? What size are they, or how are they delimited? If they're binary, are the big endian and little endian? Commented May 4, 2017 at 14:00
  • I think the guys from spakin/netpbm have a pretty neat way of extracting the metadata part for netpbm files using bufio (see their github-repo) Commented May 4, 2017 at 14:29
  • @JimB the example I gave is extracted from a real file. The metadata is as written in the example, "P6\n480 360\n255\n", and the rest (data) is just bytes. It's all encoded in utf-8. Commented May 4, 2017 at 17:27

1 Answer 1

1

You can use bufio.Reader to read the first 3 lines using the ReadLine or ReadString method and reading the rest of the file using the Read method.

After you've read the first 3 lines you can use the strings package to split the second line, and then the strconv package to parse the strings containing numbers as integers.

For example:

r := bufio.NewReader(file) line1, err := r.ReadString('\n') if err != nil { panic(err) } // repeat to read line 2 and 3 size := strings.Split(line2, " ") width, err := strconv.Atoi(size[0]) if err != nil { panic(err) } height, err := strconv.Atoi(size[1]) if err != nil { panic(err) } // repeat with line 3 

Update:

As mentioned in the comments by Adrian you can use bufio.Scanner together with the bufio.ScanWord SplitFunc to scan for the metadata.

s := bufio.NewScanner(r) s.Split(bufio.ScanWords) var count int for s.Scan() && count < 4 { switch count { case 0: magic = s.Text() case 1: if width, err = strconv.Atoi(s.Text()); err != nil { return } case 2: if height, err = strconv.Atoi(s.Text()); err != nil { return } case 3: if color, err = strconv.Atoi(s.Text()); err != nil { return } } count++ } 

https://play.golang.org/p/-rOJb_WlFf

Sign up to request clarification or add additional context in comments.

4 Comments

I tried this approach before, but the problem is: in the PPM file format, any whitespace can be used between the metadata themselves and between metadata and image data. All the metadata can be written in a single line ("P3 480 360 255") or any combination of whitespaces, not necessarily newline, and I'd like to cover all cases.
A Scanner would provide the flexibility you need if the delimiters are not consistent: golang.org/pkg/bufio/#Scanner
@GabrielCalixto I've added an example using bufio.Scanner as pointed out by @Adrian.
Thanks, guys! Actually, I need to read the first 4 infos as 1 string and 3 integers, which the current answer does, but I also need to read the rest of the file (the image pixel data) as a single byte array/slice, or maybe read byte per byte. In addition, I cannot ignore whitespace included in the pixel data, since it may be an encrypted byte, so I need to read every byte after the first 4 symbols, I cannot split all the file in lines or words, since it'll remove the whitespace included in the data.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.