| // Copyright 2013 The Go Authors. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file or at |
| // https://developers.google.com/open-source/licenses/bsd. |
| |
| package gosrc |
| |
| import ( |
| "path/filepath" |
| "regexp" |
| "time" |
| ) |
| |
| type Presentation struct { |
| Filename string |
| Files map[string][]byte |
| Updated time.Time |
| } |
| |
| type presBuilder struct { |
| filename string |
| data []byte |
| resolveURL func(fname string) string |
| fetch func(fnames []string) ([]*File, error) |
| } |
| |
| var assetPat = regexp.MustCompile(`(?m)^\.(play|code|image|background|iframe|html)\s+(?:-\S+\s+)*(\S+)`) |
| |
| func (b *presBuilder) build() (*Presentation, error) { |
| var data []byte |
| var fnames []string |
| i := 0 |
| for _, m := range assetPat.FindAllSubmatchIndex(b.data, -1) { |
| name := filepath.Clean(string(b.data[m[4]:m[5]])) |
| switch string(b.data[m[2]:m[3]]) { |
| case "iframe", "image", "background": |
| data = append(data, b.data[i:m[4]]...) |
| data = append(data, b.resolveURL(name)...) |
| case "html": |
| // TODO: sanitize and fix relative URLs in HTML. |
| data = append(data, "\nERROR: .html not supported\n"...) |
| case "play", "code": |
| data = append(data, b.data[i:m[5]]...) |
| found := false |
| for _, n := range fnames { |
| if n == name { |
| found = true |
| break |
| } |
| } |
| if !found { |
| fnames = append(fnames, name) |
| } |
| default: |
| data = append(data, "\nERROR: unknown command\n"...) |
| } |
| i = m[5] |
| } |
| data = append(data, b.data[i:]...) |
| files, err := b.fetch(fnames) |
| if err != nil { |
| return nil, err |
| } |
| pres := &Presentation{ |
| Updated: time.Now().UTC(), |
| Filename: b.filename, |
| Files: map[string][]byte{b.filename: data}, |
| } |
| for _, f := range files { |
| pres.Files[f.Name] = f.Data |
| } |
| return pres, nil |
| } |