gen.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package generators
  2. import (
  3. "archive/zip"
  4. "bytes"
  5. "encoding/xml"
  6. "github.com/kpmy/odf/model"
  7. "github.com/kpmy/odf/xmlns"
  8. "github.com/kpmy/odf/xmlns/office"
  9. "github.com/kpmy/odf/xmlns/urn"
  10. "github.com/kpmy/ypk/assert"
  11. "github.com/kpmy/ypk/halt"
  12. "io"
  13. )
  14. //Embeddable is any object that can provide []byte data for embedding in document package file (pictures for example)
  15. type Embeddable interface {
  16. MimeType() xmlns.Mime
  17. Reader() io.Reader
  18. }
  19. //Parts is a list of root "files" of document package
  20. type Parts map[string]*bytes.Buffer
  21. //Entry is a part of Manifest
  22. type Entry struct {
  23. MediaType string `xml:"manifest:media-type,attr"`
  24. FullPath string `xml:"manifest:full-path,attr"`
  25. }
  26. //Manifest file structure, contains descriptors for any parts of document
  27. type Manifest struct {
  28. XMLName xml.Name
  29. NS string `xml:"xmlns:manifest,attr"`
  30. Entries []Entry `xml:"manifest:file-entry"`
  31. }
  32. func (m *Manifest) init(mimetype xmlns.Mime) {
  33. m.XMLName.Local = "manifest:manifest"
  34. m.NS = urn.Manifest
  35. m.Entries = append(m.Entries, Entry{MediaType: string(mimetype), FullPath: "/"})
  36. }
  37. func docParts(m model.Model) (ret Parts) {
  38. ret = make(map[string]*bytes.Buffer)
  39. rd := m.NewReader()
  40. rd.Pos(m.Root())
  41. for !rd.Eol() {
  42. l := rd.Read()
  43. buf := new(bytes.Buffer)
  44. buf.WriteString(xml.Header)
  45. switch l.Name() {
  46. case office.DocumentContent:
  47. ret[xmlns.Content] = buf
  48. case office.DocumentStyles:
  49. ret[xmlns.Styles] = buf
  50. case office.DocumentMeta:
  51. ret[xmlns.Meta] = buf
  52. default:
  53. halt.As(100, l.Name())
  54. }
  55. enc := xml.NewEncoder(buf)
  56. err := enc.Encode(l)
  57. assert.For(err == nil, 60, err)
  58. }
  59. return
  60. }
  61. //GeneratePackage builds a zip-archived content of document model and embedded files and writes content to target Writer
  62. func GeneratePackage(m model.Model, embed map[string]Embeddable, out io.Writer, mimetype xmlns.Mime) {
  63. z := zip.NewWriter(out)
  64. defer z.Close()
  65. mime := &zip.FileHeader{Name: xmlns.Mimetype, Method: zip.Store} //файл mimetype не надо сжимать, режим Store
  66. if w, err := z.CreateHeader(mime); err == nil {
  67. bytes.NewBufferString(string(mimetype)).WriteTo(w)
  68. } else {
  69. halt.As(100, err)
  70. }
  71. manifest := &Manifest{}
  72. manifest.init(mimetype)
  73. for k, v := range docParts(m) {
  74. if w, err := z.Create(k); err == nil {
  75. v.WriteTo(w)
  76. manifest.Entries = append(manifest.Entries, Entry{MediaType: xmlns.MimeDefault, FullPath: k})
  77. } else {
  78. halt.As(100, err)
  79. }
  80. }
  81. for k, v := range embed {
  82. if w, err := z.Create(k); err == nil {
  83. _, err = io.Copy(w, v.Reader())
  84. assert.For(err == nil, 60)
  85. manifest.Entries = append(manifest.Entries, Entry{MediaType: string(v.MimeType()), FullPath: k})
  86. } else {
  87. halt.As(100, err)
  88. }
  89. }
  90. if w, err := z.Create(xmlns.Manifest); err == nil {
  91. w.Write([]byte(xml.Header))
  92. enc := xml.NewEncoder(w)
  93. err = enc.Encode(manifest)
  94. assert.For(err == nil, 60, err)
  95. }
  96. }