// Copyright 2017 FoxyUtils ehf. All rights reserved. // // Use of this software package and source code is governed by the terms of the // UniDoc End User License Agreement (EULA) that is available at: // https://unidoc.io/eula/ // A trial license code for evaluation can be obtained at https://unidoc.io. package unioffice import ( "fmt" "strings" "github.com/unidoc/unioffice/algo" ) // Common filenames used in zip packages. const ( ContentTypesFilename = "[Content_Types].xml" BaseRelsFilename = "_rels/.rels" ) // DocType represents one of the three document types supported (docx/xlsx/pptx) type DocType byte // Document Type constants const ( Unknown DocType = iota DocTypeSpreadsheet DocTypeDocument DocTypePresentation ) // RelativeFilename returns a filename relative to the source file referenced // from a relationships file. Index is used in some cases for files which there // may be more than one of (e.g. worksheets/drawings/charts) func RelativeFilename(dt DocType, relToTyp, typ string, index int) string { orig := AbsoluteFilename(dt, typ, index) if relToTyp == "" { return orig } relTo := AbsoluteFilename(dt, relToTyp, index) relToSp := strings.Split(relTo, "/") origSp := strings.Split(orig, "/") // determine how many segments match matching := 0 for i := 0; i < len(relToSp); i++ { if relToSp[i] == origSp[i] { matching++ } if i+1 == len(origSp) { break } } relToSp = relToSp[matching:] origSp = origSp[matching:] nm := len(relToSp) - 1 if nm > 0 { return algo.RepeatString("../", nm) + strings.Join(origSp, "/") } return strings.Join(origSp, "/") } // AbsoluteFilename returns the full path to a file from the root of the zip // container. Index is used in some cases for files which there may be more than // one of (e.g. worksheets/drawings/charts) func AbsoluteFilename(dt DocType, typ string, index int) string { switch typ { case CorePropertiesType: return "docProps/core.xml" case CustomPropertiesType: return "docProps/custom.xml" case ExtendedPropertiesType, ExtendedPropertiesTypeStrict: return "docProps/app.xml" case ThumbnailType, ThumbnailTypeStrict: return "docProps/thumbnail.jpeg" case CustomXMLType: return fmt.Sprintf("customXml/item%d.xml", index) case PresentationPropertiesType: return "ppt/presProps.xml" case ViewPropertiesType: switch dt { case DocTypePresentation: return "ppt/viewProps.xml" case DocTypeSpreadsheet: return "xl/viewProps.xml" case DocTypeDocument: return "word/viewProps.xml" } case TableStylesType: switch dt { case DocTypePresentation: return "ppt/tableStyles.xml" case DocTypeSpreadsheet: return "xl/tableStyles.xml" case DocTypeDocument: return "word/tableStyles.xml" } case HyperLinkType: return "" case OfficeDocumentType, OfficeDocumentTypeStrict: switch dt { case DocTypeSpreadsheet: return "xl/workbook.xml" case DocTypeDocument: return "word/document.xml" case DocTypePresentation: return "ppt/presentation.xml" default: Log("unsupported type %s pair and %v", typ, dt) } case ThemeType, ThemeTypeStrict, ThemeContentType: switch dt { case DocTypeSpreadsheet: return fmt.Sprintf("xl/theme/theme%d.xml", index) case DocTypeDocument: return fmt.Sprintf("word/theme/theme%d.xml", index) case DocTypePresentation: return fmt.Sprintf("ppt/theme/theme%d.xml", index) default: Log("unsupported type %s pair and %v", typ, dt) } case StylesType, StylesTypeStrict: switch dt { case DocTypeSpreadsheet: return "xl/styles.xml" case DocTypeDocument: return "word/styles.xml" case DocTypePresentation: return "ppt/styles.xml" default: Log("unsupported type %s pair and %v", typ, dt) } case ChartType, ChartTypeStrict, ChartContentType: switch dt { case DocTypeSpreadsheet: return fmt.Sprintf("xl/charts/chart%d.xml", index) case DocTypeDocument: return fmt.Sprintf("word/charts/chart%d.xml", index) case DocTypePresentation: return fmt.Sprintf("ppt/charts/chart%d.xml", index) default: Log("unsupported type %s pair and %v", typ, dt) } case TableType, TableTypeStrict, TableContentType: return fmt.Sprintf("xl/tables/table%d.xml", index) case DrawingType, DrawingTypeStrict, DrawingContentType: switch dt { case DocTypeSpreadsheet: return fmt.Sprintf("xl/drawings/drawing%d.xml", index) default: Log("unsupported type %s pair and %v", typ, dt) } case CommentsType, CommentsTypeStrict, CommentsContentType: switch dt { case DocTypeSpreadsheet: return fmt.Sprintf("xl/comments%d.xml", index) default: Log("unsupported type %s pair and %v", typ, dt) } case VMLDrawingType, VMLDrawingTypeStrict, VMLDrawingContentType: switch dt { case DocTypeSpreadsheet: return fmt.Sprintf("xl/drawings/vmlDrawing%d.vml", index) default: Log("unsupported type %s pair and %v", typ, dt) } case ImageType, ImageTypeStrict: switch dt { case DocTypeDocument: return fmt.Sprintf("word/media/image%d.png", index) case DocTypeSpreadsheet: return fmt.Sprintf("xl/media/image%d.png", index) case DocTypePresentation: return fmt.Sprintf("ppt/media/image%d.png", index) default: Log("unsupported type %s pair and %v", typ, dt) } // SML case WorksheetType, WorksheetTypeStrict, WorksheetContentType: return fmt.Sprintf("xl/worksheets/sheet%d.xml", index) case SharedStringsType, SharedStringsTypeStrict, SharedStringsContentType: return "xl/sharedStrings.xml" // WML case FontTableType, FontTableTypeStrict: return "word/fontTable.xml" case EndNotesType, EndNotesTypeStrict: return "word/endnotes.xml" case FootNotesType, FootNotesTypeStrict: return "word/footnotes.xml" case NumberingType, NumberingTypeStrict: return "word/numbering.xml" case WebSettingsType, WebSettingsTypeStrict: return "word/webSettings.xml" case SettingsType, SettingsTypeStrict: return "word/settings.xml" case HeaderType, HeaderTypeStrict: return fmt.Sprintf("word/header%d.xml", index) case FooterType, FooterTypeStrict: return fmt.Sprintf("word/footer%d.xml", index) // PML case SlideType, SlideTypeStrict: return fmt.Sprintf("ppt/slides/slide%d.xml", index) case SlideLayoutType: return fmt.Sprintf("ppt/slideLayouts/slideLayout%d.xml", index) case SlideMasterType: return fmt.Sprintf("ppt/slideMasters/slideMaster%d.xml", index) case HandoutMasterType: return fmt.Sprintf("ppt/handoutMasters/handoutMaster%d.xml", index) case NotesMasterType: return fmt.Sprintf("ppt/notesMasters/notesMaster%d.xml", index) default: Log("unsupported type %s", typ) } return "" } // RelativeImageFilename returns an image filename relative to the source file referenced // from a relationships file. It is identical to RelativeFilename but is used particularly for images // in order to handle different image formats. func RelativeImageFilename(dt DocType, relToTyp, typ string, index int, fileExtension string) string { filename := RelativeFilename(dt, relToTyp, typ, index) // replace "png" with the actual file extension return filename[0:len(filename)-3] + fileExtension } // AbsoluteImageFilename returns the full path to an image from the root of the // zip container. func AbsoluteImageFilename(dt DocType, index int, fileExtension string) string { filename := AbsoluteFilename(dt, ImageType, index) // replace "png" with the actual file extension return filename[0:len(filename)-3] + fileExtension }