github.com/readium/readium-lcp-server@v0.0.0-20240509124024-799e77a0bbd6/epub/writer.go (about)

     1  // Copyright (c) 2016 Readium Foundation
     2  //
     3  // Redistribution and use in source and binary forms, with or without modification,
     4  // are permitted provided that the following conditions are met:
     5  //
     6  // 1. Redistributions of source code must retain the above copyright notice, this
     7  //    list of conditions and the following disclaimer.
     8  // 2. Redistributions in binary form must reproduce the above copyright notice,
     9  //    this list of conditions and the following disclaimer in the documentation and/or
    10  //    other materials provided with the distribution.
    11  // 3. Neither the name of the organization nor the names of its contributors may be
    12  //    used to endorse or promote products derived from this software without specific
    13  //    prior written permission
    14  //
    15  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    16  // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    17  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    18  // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    19  // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    20  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    21  // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    22  // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    23  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    24  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
    25  
    26  package epub
    27  
    28  import (
    29  	"archive/zip"
    30  	"io"
    31  
    32  	"github.com/readium/readium-lcp-server/xmlenc"
    33  )
    34  
    35  type Writer struct {
    36  	w *zip.Writer
    37  }
    38  
    39  func (w *Writer) WriteHeader() error {
    40  	return writeMimetype(w.w)
    41  }
    42  
    43  func (w *Writer) AddResource(path string, storeMethod uint16) (io.Writer, error) {
    44  	return w.w.CreateHeader(&zip.FileHeader{
    45  		Name:   path,
    46  		Method: storeMethod,
    47  	})
    48  }
    49  
    50  func (w *Writer) Copy(r *Resource) error {
    51  	fw, err := w.AddResource(r.Path, r.StorageMethod)
    52  	if err != nil {
    53  		return err
    54  	}
    55  	_, err = io.Copy(fw, r.Contents)
    56  	return err
    57  }
    58  
    59  func (w *Writer) WriteEncryption(enc *xmlenc.Manifest) error {
    60  	fw, err := w.AddResource(EncryptionFile, zip.Deflate)
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	return enc.Write(fw)
    66  
    67  }
    68  
    69  func (w *Writer) Close() error {
    70  	return w.w.Close()
    71  }
    72  
    73  func NewWriter(w io.Writer) *Writer {
    74  	return &Writer{
    75  		w: zip.NewWriter(w),
    76  	}
    77  }
    78  
    79  func (ep Epub) Write(dst io.Writer) error {
    80  	w := NewWriter(dst)
    81  
    82  	err := w.WriteHeader()
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	for _, res := range ep.Resource {
    88  		if res.Path != "mimetype" {
    89  			fw, err := w.AddResource(res.Path, res.StorageMethod)
    90  			if err != nil {
    91  				return err
    92  			}
    93  			_, err = io.Copy(fw, res.Contents)
    94  			if err != nil {
    95  				return err
    96  			}
    97  		}
    98  	}
    99  
   100  	if ep.Encryption != nil {
   101  		writeEncryption(ep, w)
   102  	}
   103  
   104  	return w.Close()
   105  }
   106  
   107  func writeEncryption(ep Epub, w *Writer) error {
   108  	return w.WriteEncryption(ep.Encryption)
   109  }
   110  
   111  func writeMimetype(w *zip.Writer) error {
   112  	fh := &zip.FileHeader{
   113  		Name:   "mimetype",
   114  		Method: zip.Store,
   115  	}
   116  	wf, err := w.CreateHeader(fh)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	wf.Write([]byte(ContentType_EPUB))
   122  
   123  	return nil
   124  }