func lookupFunc(instruction byte, buf *bytes.Buffer) instruction { const high_2_bits = 0xc0 var restore bool // Special case the 3 opcodes that have their argument encoded in the opcode itself. switch instruction & high_2_bits { case DW_CFA_advance_loc: instruction = DW_CFA_advance_loc restore = true case DW_CFA_offset: instruction = DW_CFA_offset restore = true case DW_CFA_restore: instruction = DW_CFA_restore restore = true } if restore { // Restore the last byte as it actually contains the argument for the opcode. err := buf.UnreadByte() if err != nil { panic("Could not unread byte") } } fn, ok := fnlookup[instruction] if !ok { panic(fmt.Sprintf("Encountered an unexpected DWARF CFA opcode: %#v", instruction)) } return fn }
func parse(r io.Reader) (*Match, error) { cmd := exec.Command("pdftotext", "-q", "-enc", "UTF-8", "-eol", "unix", "-layout", "-", "-") cmd.Stdin = r stdout := new(bytes.Buffer) cmd.Stdout = stdout stderr := new(bytes.Buffer) cmd.Stderr = stderr err := cmd.Run() if err != nil { return nil, err } m := new(Match) m.Results = make(map[Division][]Result) for { if err := parsePage(stdout, m); err != nil { return nil, err } if _, err := stdout.ReadByte(); err == io.EOF { return m, nil } else { stdout.UnreadByte() } } }
func decodeNextFrom(buffer *bytes.Buffer) (Bencodable, error) { nextByte, err := buffer.ReadByte() if err != nil { return nil, err } buffer.UnreadByte() var result Bencodable switch nextByte { case 'i': result, err = decodeNextIntFrom(buffer) case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': result, err = decodeNextStringFrom(buffer) case 'l': result, err = decodeNextListFrom(buffer) case 'd': result, err = decodeNextDictFrom(buffer) default: err = errors.New(fmt.Sprintf( "Unexpected initial byte in bencoded data: %v", strconv.Quote(string(nextByte)))) } if err != nil { return nil, err } return result, nil }
func decodeNextDictFrom(buffer *bytes.Buffer) (Dict, error) { initial, err := buffer.ReadByte() if initial != 'd' || err != nil { panic("How is this not a dictionary?") } result := make(Dict, 0) AccumulateItems: for { nextByte, err := buffer.ReadByte() switch { case err != nil: return nil, err case nextByte == 'e': break AccumulateItems default: buffer.UnreadByte() key, err := decodeNextStringFrom(buffer) if err != nil { return nil, err } value, err := decodeNextFrom(buffer) if err != nil { return nil, err } result[key] = value } } return result, nil }
func decodeNextListFrom(buffer *bytes.Buffer) (List, error) { initial, err := buffer.ReadByte() if initial != 'l' || err != nil { panic("How is this not a list?") } result := make(List, 0) AccumulateItems: for { nextByte, err := buffer.ReadByte() switch { case err != nil: return nil, err case nextByte == 'e': break AccumulateItems default: buffer.UnreadByte() value, err := decodeNextFrom(buffer) if err != nil { return nil, err } result = append(result, value) } } return result, nil }
func consume(r *bytes.Buffer, b byte) bool { got, err := r.ReadByte() if err != nil { return false } if got != b { r.UnreadByte() return false } return true }
func readNumber(buf *bytes.Buffer) (token.Token, error) { value := []byte{} for { b, err := buf.ReadByte() if err != nil { if err == io.EOF { return newNumberToken(string(value)), nil } return token.Token{}, err } switch b { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': value = append(value, b) default: buf.UnreadByte() return newNumberToken(string(value)), nil } } }
func parsePage(r *bytes.Buffer, m *Match) error { ds, err := r.ReadString(byte(' ')) if err != nil { return nil } ds = strings.ToLower(ds[0 : len(ds)-1]) var d Division switch ds { case "classic": d = Classic case "standard": d = Standard case "production": d = Production case "open": d = Open case "revolver": d = Revolver default: _, err := r.ReadBytes(ff) // Skip page return err } // TODO(flowlo): Maybe match for those lines, // to make sure we're dealing with a nice file. r.ReadBytes(lf) // Skip rest of first line, usually "-- Overall Match Results" r.ReadBytes(lf) // Skip line, usually name of the Match r.ReadBytes(lf) // Skip line, usually print timestamp of the PDF r.ReadBytes(lf) // Skip empty line r.ReadBytes(lf) // Skip line, usually a descriptive headline r.ReadBytes(lf) // Skip empty line buf := new(bytes.Buffer) c := 1 for { b, err := r.ReadByte() if err != nil { return err } r.UnreadByte() if b == byte('\n') { break } l, err := r.ReadBytes(byte('\n')) if err != nil { return err } buf.Reset() buf.Write(l) sc := bufio.NewScanner(buf) sc.Split(bufio.ScanWords) res := Result{} // Read rank. if !sc.Scan() { return ErrNoToken } i, err := strconv.Atoi(sc.Text()) if err != nil { return err } if i != len(m.Results[d])+1 { return fmt.Errorf("expected rank %d but got %d", len(m.Results[d]), i) } // Read percentage. if !sc.Scan() { return ErrNoToken } dotted := strings.Replace(sc.Text(), ",", ".", 1) f, err := strconv.ParseFloat(dotted, 64) if err != nil { return err } res.Percent = f // Read points. if !sc.Scan() { return ErrNoToken } dotted = strings.Replace(sc.Text(), ",", ".", 1) f, err = strconv.ParseFloat(dotted, 64) if err != nil { return err } res.Points = f // Read MOS number. if !sc.Scan() { return ErrNoToken } i, err = strconv.Atoi(sc.Text()) if err != nil { return err } res.MosNumber = i // Read name. sc.Split(scanThreeSpaces) if !sc.Scan() { return ErrNoToken } res.Name = sc.Text() sc.Split(bufio.ScanWords) if !sc.Scan() { return ErrNoToken } res.Flags = sc.Text() res.CountryCode = "" if len(res.Flags) > 2 { i := sort.SearchStrings(countryCodes[:], res.Flags) if i < len(countryCodes) && countryCodes[i] == res.Flags { res.CountryCode = res.Flags res.Flags = "" goto finish } } if !sc.Scan() { if res.CountryCode == "" { return ErrNoToken } } else { res.CountryCode = sc.Text() } finish: c++ fmt.Printf("%+v\n", res) m.Results[d] = append(m.Results[d], res) } for { s, err := r.ReadString(lf) // Skip empty line if err != nil { return err } if len(s) == 0 { continue } if strings.Contains(s, "used") { _, err := r.ReadBytes(ff) // Skip footer return err } } return nil }
func decodeNextStringFrom(buffer *bytes.Buffer) (String, error) { firstByte, err := buffer.ReadByte() if err != nil { return "", err } if firstByte == '0' { // must be null string lastByte, err := buffer.ReadByte() switch { case err != nil: return "", err case lastByte != ':': return "", errors.New("Unexpected leading zero in non-{empty string}.") default: return "", nil } } buffer.UnreadByte() digits := []byte{} AccumulatingDigits: for { nextByte, err := buffer.ReadByte() if err != nil { return "", err } switch nextByte { case ':': break AccumulatingDigits case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': digits = append(digits, nextByte) default: return "", errors.New(fmt.Sprintf( "Unexpected byte in integer value: %v", strconv.Quote(string(nextByte)))) } } strLen, err := strconv.ParseInt(string(digits), 10, 64) if err != nil { return "", err } if strLen <= 0 { panic("strLen should not be able to be <= 0 here.") } contents := make([]byte, strLen) n, err := buffer.Read(contents) if err != nil { return "", err } if int64(n) != strLen { return "", errors.New("Declared string length greater than remaining input.") } return String(contents), nil }
func decodeNextIntFrom(buffer *bytes.Buffer) (Int, error) { initial, err := buffer.ReadByte() if initial != 'i' || err != nil { panic("How is this not an integer?") } firstByte, err := buffer.ReadByte() if err != nil { return -1, err } isNegative := false InterpretingInitial: for { switch firstByte { case '-': if !isNegative { isNegative = true firstByte, err = buffer.ReadByte() if err != nil { return -1, err } continue InterpretingInitial } else { return -1, errors.New("Unexpected \"--\" in integer value.") } case '0': // Leading zero is only allowed for value "i0e". if isNegative { return -1, errors.New("Unexpected \"-0\" in integer value.") } remainingByte, err := buffer.ReadByte() if err != nil { return -1, err } if remainingByte != byte('e') { return -1, errors.New("Unexpected leading zero in integer value.") } return 0, nil default: buffer.UnreadByte() break InterpretingInitial } } digits := []byte{} AccumulatingDigits: for { nextByte, err := buffer.ReadByte() if err != nil { return -1, err } switch nextByte { case 'e': break AccumulatingDigits case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': digits = append(digits, nextByte) default: return -1, errors.New(fmt.Sprintf( "Unexpected byte in integer value: %v", nextByte)) } } digitValue, err := strconv.ParseInt(string(digits), 10, 64) if err != nil { return -1, err } if digitValue <= 0 { panic("digitValue should not be able to be <= 0 here.") } if !isNegative { return Int(digitValue), nil } else { return Int(-digitValue), nil } }