diff --git a/.eslintignore b/.eslintignore index ed0dbe59977..4bc6090f32f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -85,7 +85,6 @@ plugin_types/ readme/ packages/react-native-vosk/lib/ packages/lib/countable/Countable.js -packages/onenote-converter/pkg/onenote_converter.js # AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD packages/app-cli/app/LinkSelector.js @@ -1175,8 +1174,6 @@ packages/lib/services/interop/InteropService_Importer_Md.test.js packages/lib/services/interop/InteropService_Importer_Md.js packages/lib/services/interop/InteropService_Importer_Md_frontmatter.test.js packages/lib/services/interop/InteropService_Importer_Md_frontmatter.js -packages/lib/services/interop/InteropService_Importer_OneNote.test.js -packages/lib/services/interop/InteropService_Importer_OneNote.js packages/lib/services/interop/InteropService_Importer_Raw.test.js packages/lib/services/interop/InteropService_Importer_Raw.js packages/lib/services/interop/Module.test.js diff --git a/.github/scripts/run_ci.sh b/.github/scripts/run_ci.sh index e644c3bda3a..0ddf5e4fb30 100755 --- a/.github/scripts/run_ci.sh +++ b/.github/scripts/run_ci.sh @@ -67,7 +67,6 @@ echo "IS_MACOS=$IS_MACOS" echo "Node $( node -v )" echo "Npm $( npm -v )" echo "Yarn $( yarn -v )" -echo "Rust $( rustc --version )" # ============================================================================= # Install packages diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index c553b2315b0..988cf855bd5 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -26,8 +26,6 @@ jobs: node-version: '18' cache: 'yarn' - - uses: dtolnay/rust-toolchain@stable - - name: Install Yarn run: | corepack enable diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index ca2e938271b..3162390d572 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -69,7 +69,6 @@ jobs: - uses: actions/checkout@v4 - uses: olegtarasov/get-tag@v2.1.3 - - uses: dtolnay/rust-toolchain@stable - uses: actions/setup-node@v4 with: # We need to pin the version to 18.15, because 18.16+ fails with this error: diff --git a/.gitignore b/.gitignore index b5d02cf90bb..1fe3d501a4e 100644 --- a/.gitignore +++ b/.gitignore @@ -1151,8 +1151,6 @@ packages/lib/services/interop/InteropService_Importer_Md.test.js packages/lib/services/interop/InteropService_Importer_Md.js packages/lib/services/interop/InteropService_Importer_Md_frontmatter.test.js packages/lib/services/interop/InteropService_Importer_Md_frontmatter.js -packages/lib/services/interop/InteropService_Importer_OneNote.test.js -packages/lib/services/interop/InteropService_Importer_OneNote.js packages/lib/services/interop/InteropService_Importer_Raw.test.js packages/lib/services/interop/InteropService_Importer_Raw.js packages/lib/services/interop/Module.test.js diff --git a/Dockerfile.server b/Dockerfile.server index 8dff0e0008b..5d0b7ab4b33 100644 --- a/Dockerfile.server +++ b/Dockerfile.server @@ -35,9 +35,6 @@ COPY packages/utils ./packages/utils COPY packages/lib ./packages/lib COPY packages/server ./packages/server -# We don't want to build onenote-converter since it is not used by the server -RUN sed --in-place '/onenote-converter/d' ./packages/lib/package.json - # For some reason there's both a .yarn/cache and .yarn/berry/cache that are # being generated, and both have the same content. Not clear why it does this # but we can delete it anyway. We can delete the cache because we use diff --git a/joplin.code-workspace b/joplin.code-workspace index 117bf6a25e2..c108fda8fda 100644 --- a/joplin.code-workspace +++ b/joplin.code-workspace @@ -5,9 +5,6 @@ }, ], "settings": { - "rust-analyzer.linkedProjects": [ - "./packages/onenote-converter/Cargo.toml", - ], "files.exclude": { "_mydocs/mdtest/": true, "_releases/": true, diff --git a/packages/app-cli/tests/support/onenote/bug_broken_character.zip b/packages/app-cli/tests/support/onenote/bug_broken_character.zip deleted file mode 100644 index b29247f6c5a..00000000000 Binary files a/packages/app-cli/tests/support/onenote/bug_broken_character.zip and /dev/null differ diff --git a/packages/app-cli/tests/support/onenote/complex_notes.zip b/packages/app-cli/tests/support/onenote/complex_notes.zip deleted file mode 100644 index d4ab2d717bc..00000000000 Binary files a/packages/app-cli/tests/support/onenote/complex_notes.zip and /dev/null differ diff --git a/packages/app-cli/tests/support/onenote/group_sections.zip b/packages/app-cli/tests/support/onenote/group_sections.zip deleted file mode 100644 index 6abb5a2640c..00000000000 Binary files a/packages/app-cli/tests/support/onenote/group_sections.zip and /dev/null differ diff --git a/packages/app-cli/tests/support/onenote/many_svgs.html b/packages/app-cli/tests/support/onenote/many_svgs.html deleted file mode 100644 index 56d58ff024d..00000000000 --- a/packages/app-cli/tests/support/onenote/many_svgs.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - Created on OneNote App - - - - - - -

 

-

 

-

 

-
- - - - - \ No newline at end of file diff --git a/packages/app-cli/tests/support/onenote/simple_notebook.zip b/packages/app-cli/tests/support/onenote/simple_notebook.zip deleted file mode 100644 index bec29b3537a..00000000000 Binary files a/packages/app-cli/tests/support/onenote/simple_notebook.zip and /dev/null differ diff --git a/packages/app-cli/tests/support/onenote/subpages.zip b/packages/app-cli/tests/support/onenote/subpages.zip deleted file mode 100644 index dc2c054be01..00000000000 Binary files a/packages/app-cli/tests/support/onenote/subpages.zip and /dev/null differ diff --git a/packages/app-cli/tests/support/onenote/subsections.zip b/packages/app-cli/tests/support/onenote/subsections.zip deleted file mode 100644 index 624307c7861..00000000000 Binary files a/packages/app-cli/tests/support/onenote/subsections.zip and /dev/null differ diff --git a/packages/app-cli/tests/support/onenote/svg_with_text_and_style.html b/packages/app-cli/tests/support/onenote/svg_with_text_and_style.html deleted file mode 100644 index 317152dec4e..00000000000 --- a/packages/app-cli/tests/support/onenote/svg_with_text_and_style.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - -
- - - My - cat - is - Grumpy! - -
- - \ No newline at end of file diff --git a/packages/app-desktop/gui/Root.tsx b/packages/app-desktop/gui/Root.tsx index 25f39c90782..ef0d5727760 100644 --- a/packages/app-desktop/gui/Root.tsx +++ b/packages/app-desktop/gui/Root.tsx @@ -25,7 +25,6 @@ const { ResourceScreen } = require('./ResourceScreen.js'); import Navigator from './Navigator'; import WelcomeUtils from '@joplin/lib/WelcomeUtils'; import JoplinCloudLoginScreen from './JoplinCloudLoginScreen'; -import InteropService from '@joplin/lib/services/interop/InteropService'; import WindowCommandsAndDialogs from './WindowCommandsAndDialogs/WindowCommandsAndDialogs'; import { defaultWindowId, stateUtils, WindowState } from '@joplin/lib/reducer'; import bridge from '../services/bridge'; @@ -92,9 +91,6 @@ async function initialize() { type: 'NOTE_VISIBLE_PANES_SET', panes: Setting.value('noteVisiblePanes'), }); - - InteropService.instance().document = document; - InteropService.instance().xmlSerializer = new XMLSerializer(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied diff --git a/packages/lib/BaseModel.ts b/packages/lib/BaseModel.ts index 79af5da22e0..97eb093e512 100644 --- a/packages/lib/BaseModel.ts +++ b/packages/lib/BaseModel.ts @@ -1,11 +1,11 @@ import paginationToSql from './models/utils/paginationToSql'; import Database from './database'; +import uuid from './uuid'; import time from './time'; import JoplinDatabase, { TableField } from './JoplinDatabase'; import { LoadOptions, SaveOptions } from './models/utils/types'; import ActionLogger, { ItemActionType as ItemActionType } from './utils/ActionLogger'; import { BaseItemEntity, SqlQuery } from './services/database/types'; -import uuid from './uuid'; const Mutex = require('async-mutex').Mutex; // New code should make use of this enum @@ -80,8 +80,6 @@ class BaseModel { ['TYPE_COMMAND', ModelType.Command], ]; - private static uuidGenerator: ()=> string = uuid.create; - public static TYPE_NOTE = ModelType.Note; public static TYPE_FOLDER = ModelType.Folder; public static TYPE_SETTING = ModelType.Setting; @@ -578,7 +576,7 @@ class BaseModel { if (options.isNew) { if (this.useUuid() && !o.id) { - modelId = this.generateUuid(); + modelId = uuid.create(); o.id = modelId; } @@ -759,15 +757,6 @@ class BaseModel { return this.db_; } - public static generateUuid() { - return this.uuidGenerator(); - } - - public static setIdGenerator(generator: ()=> string) { - const previous = this.uuidGenerator; - this.uuidGenerator = generator; - return previous; - } // static isReady() { // return !!this.db_; // } diff --git a/packages/lib/package.json b/packages/lib/package.json index ed56c4bba28..467a0910a6c 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -17,11 +17,9 @@ }, "devDependencies": { "@testing-library/react-hooks": "8.0.1", - "@types/adm-zip": "0.5.5", "@types/fs-extra": "11.0.4", "@types/jest": "29.5.12", "@types/js-yaml": "4.0.9", - "@types/jsdom": "21.1.6", "@types/markdown-it": "13.0.9", "@types/mustache": "4.2.5", "@types/node": "18.19.42", @@ -31,7 +29,6 @@ "canvas": "2.11.2", "clean-html": "1.5.0", "jest": "29.7.0", - "jsdom": "23.2.0", "pdfjs-dist": "3.11.174", "react": "18.3.1", "react-test-renderer": "18.3.1", @@ -47,13 +44,11 @@ "@joplin/fork-sax": "^1.2.56", "@joplin/fork-uslug": "^1.0.17", "@joplin/htmlpack": "~3.2", - "@joplin/onenote-converter": "0.0.1", "@joplin/renderer": "~3.2", "@joplin/turndown": "^4.0.74", "@joplin/turndown-plugin-gfm": "^1.0.56", "@joplin/utils": "~3.2", "@types/nanoid": "3.0.0", - "adm-zip": "0.5.12", "async-mutex": "0.5.0", "base-64": "1.0.0", "base64-stream": "1.0.0", diff --git a/packages/lib/services/interop/InteropService.ts b/packages/lib/services/interop/InteropService.ts index cd9696c4617..9b76daaba1c 100644 --- a/packages/lib/services/interop/InteropService.ts +++ b/packages/lib/services/interop/InteropService.ts @@ -30,8 +30,6 @@ export default class InteropService { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied private eventEmitter_: any = null; private static instance_: InteropService; - private document_: Document; - private xmlSerializer_: XMLSerializer; public static instance(): InteropService { if (!this.instance_) this.instance_ = new InteropService(); @@ -135,14 +133,6 @@ export default class InteropService { isNoteArchive: false, // Tells whether the file can contain multiple notes (eg. Enex or Jex format) description: _('Text document'), }, () => new InteropService_Importer_Md()), - - makeImportModule({ - format: 'zip', - fileExtensions: ['zip'], - sources: [FileSystemItem.File], - isNoteArchive: false, // Tells whether the file can contain multiple notes (eg. Enex or Jex format) - description: _('OneNote Notebook'), - }, dynamicRequireModuleFactory('./InteropService_Importer_OneNote')), ]; const exportModules = [ @@ -199,22 +189,6 @@ export default class InteropService { this.eventEmitter_.emit('modulesChanged'); } - public set xmlSerializer(xmlSerializer: XMLSerializer) { - this.xmlSerializer_ = xmlSerializer; - } - - public get xmlSerializer() { - return this.xmlSerializer_; - } - - public set document(document: Document) { - this.document_ = document; - } - - public get document() { - return this.document_; - } - // Find the module that matches the given type ("importer" or "exporter") // and the given format. Some formats can have multiple associated importers // or exporters, such as ENEX. In this case, the one marked as "isDefault" @@ -299,8 +273,6 @@ export default class InteropService { format: 'auto', destinationFolderId: null, destinationFolder: null, - xmlSerializer: this.xmlSerializer, - document: this.document, ...options, }; diff --git a/packages/lib/services/interop/InteropService_Importer_OneNote.test.ts b/packages/lib/services/interop/InteropService_Importer_OneNote.test.ts deleted file mode 100644 index a0729fe210f..00000000000 --- a/packages/lib/services/interop/InteropService_Importer_OneNote.test.ts +++ /dev/null @@ -1,176 +0,0 @@ -import Note from '../../models/Note'; -import Folder from '../../models/Folder'; -import { remove, readFile } from 'fs-extra'; -import { createTempDir, setupDatabaseAndSynchronizer, supportDir, switchClient } from '../../testing/test-utils'; -import { NoteEntity } from '../database/types'; -import { MarkupToHtml } from '@joplin/renderer'; -import BaseModel from '../../BaseModel'; -import InteropService from './InteropService'; -import InteropService_Importer_OneNote from './InteropService_Importer_OneNote'; -import { JSDOM } from 'jsdom'; -import { ImportModuleOutputFormat } from './types'; - -describe('InteropService_Importer_OneNote', () => { - let tempDir: string; - async function importNote(path: string) { - const newFolder = await Folder.save({ title: 'folder' }); - const service = InteropService.instance(); - await service.import({ - outputFormat: ImportModuleOutputFormat.Markdown, - path, - destinationFolder: newFolder, - destinationFolderId: newFolder.id, - }); - const allNotes: NoteEntity[] = await Note.all(); - return allNotes; - } - beforeAll(() => { - const jsdom = new JSDOM('
'); - InteropService.instance().document = jsdom.window.document; - InteropService.instance().xmlSerializer = new jsdom.window.XMLSerializer(); - }); - beforeEach(async () => { - await setupDatabaseAndSynchronizer(1); - await switchClient(1); - tempDir = await createTempDir(); - }); - afterEach(async () => { - await remove(tempDir); - }); - it('should import a simple OneNote notebook', async () => { - const notes = await importNote(`${supportDir}/onenote/simple_notebook.zip`); - const folders = await Folder.all(); - - expect(notes.length).toBe(2); - const mainNote = notes[0]; - - expect(folders.length).toBe(3); - const parentFolder = folders.find(f => f.id === mainNote.parent_id); - expect(parentFolder.title).toBe('Section title'); - expect(folders.find(f => f.id === parentFolder.parent_id).title).toBe('Simple notebook'); - - expect(mainNote.title).toBe('Page title'); - expect(mainNote.markup_language).toBe(MarkupToHtml.MARKUP_LANGUAGE_HTML); - expect(mainNote.body).toMatchSnapshot(mainNote.title); - }); - - it('should preserve indentation of subpages in Section page', async () => { - const notes = await importNote(`${supportDir}/onenote/subpages.zip`); - - const sectionPage = notes.find(n => n.title === 'Section'); - const menuHtml = sectionPage.body.split('')[0]; - const menuLines = menuHtml.split(''); - - const pageTwo = notes.find(n => n.title === 'Page 2'); - expect(menuLines[3].trim()).toBe(`
  • ${pageTwo.title}`); - - const pageTwoA = notes.find(n => n.title === 'Page 2-a'); - expect(menuLines[4].trim()).toBe(`
  • ${pageTwoA.title}`); - - const pageTwoAA = notes.find(n => n.title === 'Page 2-a-a'); - expect(menuLines[5].trim()).toBe(`
  • ${pageTwoAA.title}`); - - const pageTwoB = notes.find(n => n.title === 'Page 2-b'); - expect(menuLines[7].trim()).toBe(`
  • ${pageTwoB.title}`); - }); - - it('should created subsections', async () => { - const notes = await importNote(`${supportDir}/onenote/subsections.zip`); - const folders = await Folder.all(); - - const parentSection = folders.find(f => f.title === 'Group Section 1'); - const subSection = folders.find(f => f.title === 'Group Section 1-a'); - const subSection1 = folders.find(f => f.title === 'Subsection 1'); - const subSection2 = folders.find(f => f.title === 'Subsection 2'); - const notesFromParentSection = notes.filter(n => n.parent_id === parentSection.id); - - expect(parentSection.id).toBe(subSection1.parent_id); - expect(parentSection.id).toBe(subSection2.parent_id); - expect(parentSection.id).toBe(subSection.parent_id); - expect(folders.length).toBe(7); - expect(notes.length).toBe(6); - expect(notesFromParentSection.length).toBe(2); - }); - - it('should expect notes to be rendered the same', async () => { - let idx = 0; - const originalIdGenerator = BaseModel.setIdGenerator(() => String(idx++)); - const notes = await importNote(`${supportDir}/onenote/complex_notes.zip`); - - const folders = await Folder.all(); - const parentSection = folders.find(f => f.title === 'Quick Notes'); - expect(folders.length).toBe(3); - expect(notes.length).toBe(7); - expect(notes.filter(n => n.parent_id === parentSection.id).length).toBe(6); - - for (const note of notes) { - expect(note.body).toMatchSnapshot(note.title); - } - BaseModel.setIdGenerator(originalIdGenerator); - }); - - it('should render the proper tree for notebook with group sections', async () => { - const notes = await importNote(`${supportDir}/onenote/group_sections.zip`); - const folders = await Folder.all(); - - const mainFolder = folders.find(f => f.title === 'Notebook created on OneNote App'); - const section = folders.find(f => f.title === 'Section'); - const sectionA1 = folders.find(f => f.title === 'Section A1'); - const sectionA = folders.find(f => f.title === 'Section A'); - const sectionB1 = folders.find(f => f.title === 'Section B1'); - const sectionB = folders.find(f => f.title === 'Section B'); - const sectionD1 = folders.find(f => f.title === 'Section D1'); - const sectionD = folders.find(f => f.title === 'Section D'); - - expect(section.parent_id).toBe(mainFolder.id); - expect(sectionA.parent_id).toBe(mainFolder.id); - expect(sectionD.parent_id).toBe(mainFolder.id); - - expect(sectionA1.parent_id).toBe(sectionA.id); - expect(sectionB.parent_id).toBe(sectionA.id); - - expect(sectionB1.parent_id).toBe(sectionB.id); - expect(sectionD1.parent_id).toBe(sectionD.id); - - expect(notes.filter(n => n.parent_id === sectionA1.id).length).toBe(2); - expect(notes.filter(n => n.parent_id === sectionB1.id).length).toBe(2); - expect(notes.filter(n => n.parent_id === sectionD1.id).length).toBe(1); - }); - - it.each([ - 'svg_with_text_and_style.html', - 'many_svgs.html', - ])('should extract svgs', async (filename: string) => { - const titleGenerator = () => { - let id = 0; - return () => { - id += 1; - return `id${id}`; - }; - }; - const filepath = `${supportDir}/onenote/${filename}`; - const content = await readFile(filepath, 'utf-8'); - - const jsdom = new JSDOM('
    '); - InteropService.instance().document = jsdom.window.document; - InteropService.instance().xmlSerializer = new jsdom.window.XMLSerializer(); - - const importer = new InteropService_Importer_OneNote(); - await importer.init('asdf', { - document: jsdom.window.document, - xmlSerializer: new jsdom.window.XMLSerializer(), - }); - - expect(importer.extractSvgs(content, titleGenerator())).toMatchSnapshot(); - }); - - it('should ignore broken characters at the start of paragraph', async () => { - let idx = 0; - const originalIdGenerator = BaseModel.setIdGenerator(() => String(idx++)); - const notes = await importNote(`${supportDir}/onenote/bug_broken_character.zip`); - - expect(notes.find(n => n.title === 'Action research - Wikipedia').body).toMatchSnapshot(); - - BaseModel.setIdGenerator(originalIdGenerator); - }); -}); diff --git a/packages/lib/services/interop/InteropService_Importer_OneNote.ts b/packages/lib/services/interop/InteropService_Importer_OneNote.ts deleted file mode 100644 index 942737073d7..00000000000 --- a/packages/lib/services/interop/InteropService_Importer_OneNote.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { ImportExportResult, ImportModuleOutputFormat, ImportOptions } from './types'; - -import InteropService_Importer_Base from './InteropService_Importer_Base'; -import { NoteEntity } from '../database/types'; -import { rtrimSlashes } from '../../path-utils'; -import * as AdmZip from 'adm-zip'; -import InteropService_Importer_Md from './InteropService_Importer_Md'; -import { join, resolve, normalize, sep, dirname } from 'path'; -import Logger from '@joplin/utils/Logger'; -import { uuidgen } from '../../uuid'; -import shim from '../../shim'; - -const logger = Logger.create('InteropService_Importer_OneNote'); - -export type SvgXml = { - title: string; - content: string; -}; - -type ExtractSvgsReturn = { - svgs: SvgXml[]; - html: string; -}; - -// See onenote-converter README.md for more information -export default class InteropService_Importer_OneNote extends InteropService_Importer_Base { - protected importedNotes: Record = {}; - private document: Document = null; - private xmlSerializer: XMLSerializer = null; - - public async init(sourcePath: string, options: ImportOptions) { - await super.init(sourcePath, options); - if (!options.document || !options.xmlSerializer) { - throw new Error('OneNote importer requires document and XMLSerializer to be able to extract SVG from HTML.'); - } - this.document = options.document; - this.xmlSerializer = options.xmlSerializer; - } - - private getEntryDirectory(unzippedPath: string, entryName: string) { - const withoutBasePath = entryName.replace(unzippedPath, ''); - return normalize(withoutBasePath).split(sep)[0]; - } - - public async exec(result: ImportExportResult) { - const sourcePath = rtrimSlashes(this.sourcePath_); - const unzipTempDirectory = await this.temporaryDirectory_(true); - const zip = new AdmZip(sourcePath); - logger.info('Unzipping files...'); - zip.extractAllTo(unzipTempDirectory, false); - - const files = zip.getEntries(); - if (files.length === 0) { - result.warnings.push('Zip file has no files.'); - return result; - } - - const tempOutputDirectory = await this.temporaryDirectory_(true); - const baseFolder = this.getEntryDirectory(unzipTempDirectory, files[0].entryName); - const notebookBaseDir = join(unzipTempDirectory, baseFolder, sep); - const outputDirectory2 = join(tempOutputDirectory, baseFolder); - - const notebookFiles = zip.getEntries().filter(e => e.name !== '.onetoc2' && e.name !== 'OneNote_RecycleBin.onetoc2'); - const { oneNoteConverter } = shim.requireDynamic('../../../onenote-converter/pkg/onenote_converter'); - - logger.info('Extracting OneNote to HTML'); - for (const notebookFile of notebookFiles) { - const notebookFilePath = join(unzipTempDirectory, notebookFile.entryName); - try { - await oneNoteConverter(notebookFilePath, resolve(outputDirectory2), notebookBaseDir); - } catch (error) { - console.error(error); - } - } - - logger.info('Extracting SVGs into files'); - await this.moveSvgToLocalFile(tempOutputDirectory); - - logger.info('Importing HTML into Joplin'); - const importer = new InteropService_Importer_Md(); - importer.setMetadata({ fileExtensions: ['html'] }); - await importer.init(tempOutputDirectory, { - ...this.options_, - format: 'html', - outputFormat: ImportModuleOutputFormat.Html, - - }); - logger.info('Finished'); - result = await importer.exec(result); - - return result; - } - - private async moveSvgToLocalFile(baseFolder: string) { - const htmlFiles = await this.getValidHtmlFiles(resolve(baseFolder)); - - for (const file of htmlFiles) { - const fileLocation = join(baseFolder, file.path); - const originalHtml = await shim.fsDriver().readFile(fileLocation); - const { svgs, html: updatedHtml } = this.extractSvgs(originalHtml, () => uuidgen(10)); - - if (!svgs || !svgs.length) continue; - - await shim.fsDriver().writeFile(fileLocation, updatedHtml, 'utf8'); - await this.createSvgFiles(svgs, join(baseFolder, dirname(file.path))); - } - } - - private async getValidHtmlFiles(baseFolder: string) { - const files = await shim.fsDriver().readDirStats(baseFolder, { recursive: true }); - const htmlFiles = files.filter(f => !f.isDirectory() && f.path.endsWith('.html')); - return htmlFiles; - } - - private async createSvgFiles(svgs: SvgXml[], svgBaseFolder: string) { - for (const svg of svgs) { - await shim.fsDriver().writeFile(join(svgBaseFolder, svg.title), svg.content, 'utf8'); - } - } - - public extractSvgs(html: string, titleGenerator: ()=> string): ExtractSvgsReturn { - const htmlDocument = this.document.implementation.createHTMLDocument('htmlDocument'); - const root = htmlDocument.createElement('html'); - const body = htmlDocument.createElement('body'); - root.appendChild(body); - root.innerHTML = html; - - // get all "top-level" SVGS (ignore nested) - const svgNodeList = root.querySelectorAll('svg'); - - if (!svgNodeList || !svgNodeList.length) { - return { svgs: [], html }; - } - - const svgs: SvgXml[] = []; - - for (const svgNode of svgNodeList) { - const title = `${titleGenerator()}.svg`; - const img = htmlDocument.createElement('img'); - img.setAttribute('style', svgNode.getAttribute('style')); - img.setAttribute('src', `./${title}`); - svgNode.removeAttribute('style'); - - svgs.push({ - title, - content: this.xmlSerializer.serializeToString(svgNode), - }); - - svgNode.parentElement.replaceChild(img, svgNode); - } - - return { - svgs, - html: this.xmlSerializer.serializeToString(root), - }; - } -} diff --git a/packages/lib/services/interop/__snapshots__/InteropService_Importer_OneNote.test.js.snap b/packages/lib/services/interop/__snapshots__/InteropService_Importer_OneNote.test.js.snap deleted file mode 100644 index a70037a0b3e..00000000000 --- a/packages/lib/services/interop/__snapshots__/InteropService_Importer_OneNote.test.js.snap +++ /dev/null @@ -1,768 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`InteropService_Importer_OneNote should expect notes to be rendered the same: A page can have any width it wants 1`] = ` -" - - A page can have any width it wants? - - - - -
    A page can have any width it wants?
    -
    quinta-feira, 25 de abril de 2024
    -
    15:01
    -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget convallis velit. Nullam at luctus libero. Phasellus id pharetra odio. Duis luctus lorem ut tellus imperdiet, a aliquet elit pretium. Donec sit amet urna et mi gravida cursus et id felis. Ut quis congue velit, eget mollis tortor. Vestibulum porttitor lobortis justo, in imperdiet leo porta id. Sed ornare ex nisi, sed laoreet nulla suscipit a. Cras nec lectus porta, fermentum quam ac, sagittis ipsum. Ut massa lacus, ornare in hendrerit sit amet, tempor quis ligula. Nulla facilisi. Maecenas quam dolor, lacinia id magna nec, blandit tincidunt ipsum. Proin placerat dui gravida, lacinia tortor eu, rhoncus ex. Pellentesque accumsan nunc id venenatis condimentum. Aenean sodales tortor id risus varius, id tincidunt libero tincidunt. Curabitur quis interdum metus.

    -

     

    -

    This is another paragraph by the right side

    -
    - - - -" -`; - -exports[`InteropService_Importer_OneNote should expect notes to be rendered the same: A page with a lot of svgs 1`] = ` -" - - A page with a lot of svgs - - - - -
    A page with a lot of svgs
    -
    quinta-feira, 25 de abril de 2024
    -
    10:40
    -

    This is a text paragraph that should apppear behind the drawings

    -
    - - - -" -`; - -exports[`InteropService_Importer_OneNote should expect notes to be rendered the same: A page with text and drawing above it 1`] = ` -" - - A page with text and drawing above it - - - - -
    A page with text and drawing above it
    -
    quinta-feira, 25 de abril de 2024
    -
    02:48
    -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget convallis velit. Nullam at luctus libero. Phasellus id pharetra odio. Duis luctus lorem ut tellus imperdiet, a aliquet elit pretium. Donec sit amet urna et mi gravida cursus et id felis. Ut quis congue velit, eget mollis tortor. Vestibulum porttitor lobortis justo, in imperdiet leo porta id. Sed ornare ex nisi, sed laoreet nulla suscipit a. Cras nec lectus porta, fermentum quam ac, sagittis ipsum. Ut massa lacus, ornare in hendrerit sit amet, tempor quis ligula. Nulla facilisi. Maecenas quam dolor, lacinia id magna nec, blandit tincidunt ipsum. Proin placerat dui gravida, lacinia tortor eu, rhoncus ex. Pellentesque accumsan nunc id venenatis condimentum. Aenean sodales tortor id risus varius, id tincidunt libero tincidunt. Curabitur quis interdum metus.

    -

    Vestibulum sed sem nec nulla tincidunt maximus. Nam nulla sapien, vestibulum ac eros a, eleifend sollicitudin lectus. Praesent pellentesque pulvinar porttitor. Morbi rutrum, erat nec blandit commodo, nunc nulla venenatis massa, at viverra leo nisi eu nisl. Sed cursus quam a sem mattis suscipit. Duis gravida tellus ut nibh congue aliquam. Nulla velit orci, pretium sed hendrerit a, vulputate in lacus. Sed vitae ligula ex.

    -

    Nullam ut ullamcorper arcu, a porta lectus. Nulla suscipit lorem et nibh viverra eleifend. Pellentesque placerat fermentum ligula. Vivamus sit amet justo quis enim convallis condimentum. Ut non aliquet dui, vel vestibulum libero. In mauris ligula, pharetra eu maximus ut, ultrices ac justo. Donec varius condimentum augue eget tincidunt. Nunc eu egestas est.

    -

    Quisque scelerisque commodo maximus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed egestas et felis consectetur bibendum. Fusce interdum purus nec commodo porta. Praesent gravida efficitur rutrum. Phasellus semper erat urna, vitae hendrerit velit dictum et. Aenean eget dignissim tellus.

    -

    Proin ullamcorper quam quis justo maximus, eget elementum justo porttitor. Duis tellus leo, vestibulum vel felis sit amet, luctus vestibulum arcu. Nullam mauris quam, consequat eget varius nec, pellentesque quis ante. Fusce vitae sollicitudin orci. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum ac rutrum ipsum. Nulla in sapien lorem. Etiam sit amet leo eros. Vestibulum lacinia ipsum lobortis lacus congue, a posuere urna sollicitudin. Donec fermentum, ipsum nec tempor dictum, mi sapien sodales mi, eget tempor diam diam ut erat. Integer euismod sit amet tortor ut sollicitudin. Etiam at elit massa. Vivamus faucibus ipsum eget neque semper, at maximus lectus posuere. Nam metus orci, ultricies et lorem at, iaculis placerat diam.

    -

    Vestibulum massa magna, pulvinar id tempus vitae, egestas at eros. Maecenas sollicitudin tincidunt est eget accumsan. Ut ut hendrerit lectus. Pellentesque efficitur lacus in nulla posuere convallis. Ut vulputate erat id odio tincidunt, rhoncus eleifend metus vulputate. Phasellus blandit sem diam, at auctor diam consectetur a. Aliquam sit amet fermentum massa, id ultrices ligula. Aenean tincidunt quam risus, vel aliquet massa tristique at. In lectus nulla, dapibus quis vulputate eu, luctus vel nunc. Duis sollicitudin consequat dui, nec placerat dolor euismod ut. Quisque posuere leo nec accumsan posuere. Vestibulum tristique gravida justo egestas vestibulum. Nunc placerat semper erat vel egestas. Mauris massa sapien, sodales vitae fringilla vel, volutpat dapibus velit.

    -

     

    -
    - - - -" -`; - -exports[`InteropService_Importer_OneNote should expect notes to be rendered the same: A simple filename 1`] = ` -" - - A simple filename - - - - -
    A simple filename
    -
    Friday, April 19, 2024
    -
    5:46 PM
    -

     

    -
    - - - -" -`; - -exports[`InteropService_Importer_OneNote should expect notes to be rendered the same: Page with more than one font size 1`] = ` -" - - Page with more than one font size - - - - -
    Page with more than one font size
    -
    segunda-feira, 29 de abril de 2024
    -
    10:27
    -

    Suspendisse vitae odio nibh. Etiam fringilla mattis dapibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce vel ultricies ligula. Sed a nunc ante. Praesent suscipit fermentum magna. Aliquam convallis porttitor lacus ac posuere. Vestibulum maximus leo vel tortor condimentum, et tristique leo maximus. Nulla elementum, augue eu sollicitudin tempus, arcu ex lacinia enim, ut posuere lectus libero non eros. Vestibulum a libero leo. Donec id leo commodo, ornare ante ac, molestie tellus. Aenean a neque quis turpis euismod porta. Quisque vulputate augue vitae orci accumsan, a lobortis leo luctus. Nunc sodales sapien vitae lacus faucibus hendrerit. In ac lacinia diam.

    -

    Nam tempor urna eget posuere mollis. Aliquam erat volutpat. Sed ipsum massa, dictum eget sagittis id, fermentum a justo. Vivamus in iaculis libero. Pellentesque malesuada felis dictum turpis placerat, at ultrices justo viverra. Praesent nisi lectus, tincidunt ut tellus in, convallis euismod urna. Phasellus molestie porttitor odio vitae efficitur. Curabitur vulputate congue tincidunt. Fusce mattis orci at porttitor fermentum. Cras eu placerat odio. Fusce eu tortor sit amet massa pretium efficitur. Nam consequat, mauris at blandit placerat, est sapien feugiat felis, quis imperdiet sapien neque in justo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus vestibulum rhoncus dolor, ut ullamcorper purus scelerisque eu. Integer sem felis, pellentesque in rutrum id, porta a ante.Vivamus finibus imperdiet massa, at interdum turpis rhoncus et. Phasellus leo nibh, mattis vel tortor at, gravida finibus felis. Donec bibendum enim euismod, dignissim ipsum eu, laoreet nisl. Ut auctor sollicitudin eros dictum gravida. Vestibulum pellentesque, ex quis vulputate efficitur, dolor metus efficitur nisl, id elementum mi nulla sit amet orci. Nam odio sem, bibendum at hendrerit finibus, vestibulum vitae dolor. In hac habitasse platea dictumst. Curabitur et ligula elit. Donec vulputate, diam non gravida efficitur, mi odio imperdiet ipsum, nec rhoncus mi nibh non magna.

    -

    Suspendisse varius enim vel odio congue sodales. Integer sit amet nisi sagittis, dapibus mi ut, tincidunt magna. Duis posuere est felis, et rhoncus magna volutpat a. Nullam tempor dignissim suscipit. Vestibulum cursus felis vitae libero pulvinar molestie. Donec at metus eget arcu blandit tincidunt. Donec purus felis, malesuada ac egestas eu, interdum sed erat. Praesent nec accumsan orci. Nunc bibendum rutrum erat, vel luctus odio. Pellentesque iaculis gravida arcu, eu consequat turpis congue sit amet. Interdum et malesuada fames ac ante ipsum primis in faucibus. Duis eget urna vel erat aliquet fringilla. Praesent vel luctus ligula, nec viverra nisl. Sed ac sem consectetur, sodales ante sodales, feugiat arcu.

    -

    It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith, his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly through the glass doors of Victory Mansions, though not quickly enough to prevent a swirl of gritty dust from entering along with him.

    The hallway smelt of boiled cabbage and old rag mats. At one end of it a coloured poster, too large for indoor display, had been tacked to the wall. It depicted simply an enormous face, more than a metre wide: the face of a man of about forty-five, with a heavy black moustache and ruggedly handsome features. Winston made for the stairs. It was no use trying the lift. Even at the best of times it was seldom working, and at present the electric current was cut off during daylight hours. It was part of the economy drive in preparation for Hate Week. The flat was seven flights up, and Winston, who was thirty-nine and had a varicose ulcer above his right ankle, went slowly, resting several times on the way. On each landing, opposite the lift-shaft, the poster with the enormous face gazed from the wall. It was one of those pictures which are so contrived that the eyes follow you about when you move. BIG BROTHER IS WATCHING YOU, the caption beneath it ran.

    Inside the flat a fruity voice was reading out a list of figures which had something to do with the production of pig-iron. The voice came from an oblong metal plaque like a dulled mirror which formed part of the surface of the right-hand wall. Winston turned a switch and the voice sank somewhat, though the words were still distinguishable. The instrument (the telescreen, it was called) could be dimmed, but there was no way of shutting it off completely. He moved over to the window: a smallish, frail figure, the meagreness of his body merely emphasized by the blue overalls which were the uniform of the party. His hair was very fair, his face naturally sanguine, his skin roughened by coarse soap and blunt razor blades and the cold of the winter that had just ended.

    -
    - - - -" -`; - -exports[`InteropService_Importer_OneNote should expect notes to be rendered the same: Quick Notes 1`] = ` -" - - - - Quick Notes - - - - - - - - - - - -" -`; - -exports[`InteropService_Importer_OneNote should expect notes to be rendered the same: text 1`] = ` -" - - text - - - - -
    text
    -
    quinta-feira, 25 de abril de 2024
    -
    15:39
    -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus egestas, enim vel tempor scelerisque, metus magna imperdiet purus, facilisis consequat mi augue eget risus. Vestibulum tincidunt lobortis turpis, id consectetur mauris consectetur et. Aliquam interdum ante ut lectus varius, ut mattis turpis tincidunt. Donec vitae sem sagittis, porta ex a, mattis tortor. Curabitur non velit suscipit, eleifend lectus quis, convallis velit. Nunc a blandit nisl. Cras rhoncus, enim a malesuada commodo, dolor dui pulvinar eros, non lobortis diam velit quis est. Donec pharetra, dolor a faucibus tincidunt, turpis dolor fermentum nibh, facilisis mollis neque urna a neque. Sed sit amet efficitur elit. Duis at elit non quam semper semper non quis mauris. Integer dignissim sodales urna, eu mattis urna viverra sit amet. In porta arcu id mauris hendrerit, in congue erat porta. In hac habitasse platea dictumst. Maecenas finibus sem pharetra blandit suscipit. Proin in nisl ac est pellentesque finibus. Cras ligula tellus, tempor eget leo in, vulputate interdum turpis.

    -

    Nam sit amet massa vehicula, elementum nisl feugiat, fermentum quam. Donec eros urna, ultrices vel fringilla suscipit, pretium non ligula. Sed sit amet pellentesque lorem, quis pharetra augue. Integer vitae sodales ex, luctus imperdiet arcu. Integer luctus urna eu urna ultricies ultricies. Aliquam sit amet maximus orci. Sed molestie vehicula vehicula. Morbi lacinia, dolor eu consectetur commodo, ipsum ante suscipit sem, eget facilisis nibh nisi venenatis magna. Donec ac risus ligula. In sit amet dapibus ante, sit amet pellentesque dolor. Nulla facilisi. Sed a nibh viverra, placerat purus at, rutrum justo. Fusce finibus consequat mattis. Sed felis tellus, consequat id nunc non, cursus tempus ligula. In hac habitasse platea dictumst. Praesent eget consectetur elit, ac mollis est.

    -

    Quisque facilisis justo diam, eget tincidunt augue lobortis non. Quisque rutrum diam sed diam feugiat, quis dictum ex bibendum. Nunc sagittis quam erat, sed pharetra nunc consequat a. Etiam in sollicitudin nunc. Aliquam non dolor laoreet ex egestas efficitur vel ut ligula. Duis mollis ornare laoreet. Nullam vitae velit feugiat leo bibendum faucibus. Morbi nisl nisl, sodales nec sodales vel, consequat in mi. Pellentesque bibendum erat iaculis dui volutpat ornare. Etiam ultricies tincidunt ipsum a congue. In at lacinia massa. Ut auctor id elit et pellentesque.

    -

    Donec ac condimentum dui, tincidunt rhoncus augue. Maecenas aliquam non nisl ac fringilla. Aliquam pulvinar enim sit amet accumsan tristique. Cras sapien ipsum, ultricies eu dui eget, efficitur ornare elit. Curabitur hendrerit mauris dolor, gravida elementum enim convallis quis. Vivamus varius luctus massa, in egestas mi egestas id. Nullam elementum scelerisque nisi sit amet pellentesque. In varius mollis risus, vel laoreet tortor. Pellentesque et blandit velit, nec auctor nunc. Aliquam quis purus vel ligula auctor rhoncus. Duis sed tempus metus. Praesent ac libero sed leo posuere feugiat id vel felis. Aenean commodo dapibus hendrerit. Sed eleifend, tortor sed placerat auctor, dolor dolor efficitur dolor, ut rhoncus eros libero sed ante. Mauris quis blandit sem. Nullam porta urna eros, at viverra sem iaculis in.

    -

     

    -
    - - - -" -`; - -exports[`InteropService_Importer_OneNote should extract svgs 1`] = ` -{ - "html": " - -
    - -
    - -", - "svgs": [ - { - "content": " - - My - cat - is - Grumpy! -", - "title": "id1.svg", - }, - ], -} -`; - -exports[`InteropService_Importer_OneNote should extract svgs 2`] = ` -{ - "html": " - - Created on OneNote App - - - - - - -

     

    -

     

    -

     

    -
    - - - - -", - "svgs": [ - { - "content": "", - "title": "id1.svg", - }, - { - "content": "", - "title": "id2.svg", - }, - { - "content": "", - "title": "id3.svg", - }, - { - "content": "", - "title": "id4.svg", - }, - { - "content": "", - "title": "id5.svg", - }, - { - "content": "", - "title": "id6.svg", - }, - { - "content": "", - "title": "id7.svg", - }, - { - "content": "", - "title": "id8.svg", - }, - { - "content": "", - "title": "id9.svg", - }, - { - "content": "", - "title": "id10.svg", - }, - { - "content": "", - "title": "id11.svg", - }, - { - "content": "", - "title": "id12.svg", - }, - { - "content": "", - "title": "id13.svg", - }, - { - "content": "", - "title": "id14.svg", - }, - { - "content": "", - "title": "id15.svg", - }, - { - "content": "", - "title": "id16.svg", - }, - { - "content": "", - "title": "id17.svg", - }, - { - "content": "", - "title": "id18.svg", - }, - { - "content": "", - "title": "id19.svg", - }, - { - "content": "", - "title": "id20.svg", - }, - { - "content": "", - "title": "id21.svg", - }, - { - "content": "", - "title": "id22.svg", - }, - { - "content": "", - "title": "id23.svg", - }, - { - "content": "", - "title": "id24.svg", - }, - { - "content": "", - "title": "id25.svg", - }, - { - "content": "", - "title": "id26.svg", - }, - { - "content": "", - "title": "id27.svg", - }, - { - "content": "", - "title": "id28.svg", - }, - { - "content": "", - "title": "id29.svg", - }, - { - "content": "", - "title": "id30.svg", - }, - { - "content": "", - "title": "id31.svg", - }, - { - "content": "", - "title": "id32.svg", - }, - { - "content": "", - "title": "id33.svg", - }, - { - "content": "", - "title": "id34.svg", - }, - { - "content": "", - "title": "id35.svg", - }, - { - "content": "", - "title": "id36.svg", - }, - { - "content": "", - "title": "id37.svg", - }, - { - "content": "", - "title": "id38.svg", - }, - { - "content": "", - "title": "id39.svg", - }, - { - "content": "", - "title": "id40.svg", - }, - { - "content": "", - "title": "id41.svg", - }, - { - "content": "", - "title": "id42.svg", - }, - { - "content": "", - "title": "id43.svg", - }, - { - "content": "", - "title": "id44.svg", - }, - { - "content": "", - "title": "id45.svg", - }, - { - "content": "", - "title": "id46.svg", - }, - { - "content": "", - "title": "id47.svg", - }, - { - "content": "", - "title": "id48.svg", - }, - { - "content": "", - "title": "id49.svg", - }, - { - "content": "", - "title": "id50.svg", - }, - { - "content": "", - "title": "id51.svg", - }, - { - "content": "", - "title": "id52.svg", - }, - { - "content": "", - "title": "id53.svg", - }, - { - "content": "", - "title": "id54.svg", - }, - { - "content": "", - "title": "id55.svg", - }, - ], -} -`; - -exports[`InteropService_Importer_OneNote should ignore broken characters at the start of paragraph 1`] = ` -" - - - - Action research - Wikipedia - - - - -
    Action research - Wikipedia
    -
    Monday, May 27, 2019
    -
    12:13 PM
    -
    -
    -

    569 revisions since 2003-05-19 (+5 days), 328 editors, 90 watchers, 18,937 pageviews (30 days), created by: Thseamon (762) · See full page statistics

    - -

    For the British charity formerly named Action Research, see Action Medical Research. For the academic journal titled Action Research, see Action Research (journal).

    -
    -

    This article needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed.
    Find sources: "Action research" – news · newspapers · books · scholar · JSTOR (May 2019) (Learn how and when to remove this template message)

    -
    -


    Action research
    seeks transformative change through the simultaneous process of taking action and doing research, which are linked together by critical reflection.Kurt Lewin, then a professor at MIT, first coined the term "action research" in 1944. In his 1946 paper "Action Research and Minority Problems" he described action research as "a comparative research on the conditions and effects of various forms of social action and research leading to social action" that uses "a spiral of steps, each of which is composed of a circle of planning, action and fact-finding about the result of the action".

    -

    Action research practitioners reflect upon the consequences of their own questions, beliefs, assumptions, and practices with the goal of understanding, developing, and improving social practices.[1] This action is designed to create three levels of change[2] (1) self-change as the only subject of action research is the person who conducting the research. This person is seeking to be better understand the effects of their action in social settings and to engage in a process of living his or her's values. The second level is a collective process of understanding change in a classroom, office, community, organization or institution. Action research enlists others and works to create a democratic sharing of voice to achieve deeper understanding of collective actions[3]. Finally action research is process of sharing finding with the community of researchers. This can be done is many ways, in journals[4], on websites, in books, videos or at conferences. The Social Publishers Foundation[5] provides support for this action research process.

    -


    Action research involves actively participating in a change situation, often via an existing organization, whilst simultaneously conducting research. Action research can also be undertaken by larger organizations or institutions, assisted or guided by professional researchers, with the aim of improving their strategies, practices and knowledge of the environments within which they practice. As designers and stakeholders, researchers work with others to propose a new course of action to help their community improve its work practices. Depending upon the nature of the people involved in the action research as well as the person(s) organizing it, there are different ways of describing action research
    [6]

    • Collaborative Action Research
    • -
    • Participatory Action Research
    • -
    • Community-Based Action Research
    • -
    • Youth Action Research
    • -
    • Action Research and Action Learning
    • -
    • Participatory Action Learning and Action Research
    • -
    • Collective Action Research
    • -
    • Action Science
    • -
    • Living Theory Action Research
    • -
    -


    There are also a set of approaches that share some properties with action research but have some different practices
    [7]

    • Appreciative Inquiry is a way of starting with what is working well and then using action research to improve it.
    • -
    • Lesson Study places the teaching of a shared lesson as the action and has a set of protocols for understanding the outcomes.
    • -
    • Practitioner Research does not have to be action research, as practitioners can engage in any form of the many forms of research.
    • -
    • Reflective Practice/Self Study is the first part of action research but does not require the practitioner to make the results public, to share the results of the learning with others.  Many of these approaches will be described in these resources.
    • -
    • Teacher Research can be any form of research that teachers do, including action research, but not limited to it. At George Mason University, teacher research is described in a way that is very similar to what most authors understand as action research. And at some point, they suggest that action research can be a synonym of teacher research.  The description of action research posted on this site is more closely aligned to what we have called reflective practice.   This shows the variation in the way that people working in the field have of conceptualizing these terms.
    • -
    • Action Inquiry draws on action research and recasts evaluation research to help navigate complexity when enacting collective leadership. Find out more about by reading this document from Scotland.
    • -
    • Improvement Science is explicitly designed to accelerate learning-by-doing. It's a more user-centered and problem-centered approached to improving teaching and learning that is highly similar to action research supported by the Carnegie Foundation for the Advancement of Teaching.
    • -
    -


    -
    - - - -" -`; - -exports[`InteropService_Importer_OneNote should import a simple OneNote notebook: Page title 1`] = ` -" - - - - Page title - - - - -
    Page title
    -
    Friday, May 3, 2024
    -
    6:30 PM
    -

    Page content

    -
    - - - -" -`; diff --git a/packages/lib/services/interop/types.ts b/packages/lib/services/interop/types.ts index 643b9ae8457..0ffd14a44ce 100644 --- a/packages/lib/services/interop/types.ts +++ b/packages/lib/services/interop/types.ts @@ -51,8 +51,6 @@ export interface ImportOptions { onProgress?: (progressState: any, progress?: any)=> void; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied onError?: (error: any)=> void; - document?: Document; - xmlSerializer?: XMLSerializer; defaultFolderTitle?: string; } diff --git a/packages/lib/shim-init-node.ts b/packages/lib/shim-init-node.ts index 3e77dc2767c..10d8b99a5af 100644 --- a/packages/lib/shim-init-node.ts +++ b/packages/lib/shim-init-node.ts @@ -17,7 +17,6 @@ import crypto from './services/e2ee/crypto'; import FileApiDriverLocal from './file-api-driver-local'; import * as mimeUtils from './mime-utils'; -import BaseItem from './models/BaseItem'; const { _ } = require('./locale'); const http = require('http'); const https = require('https'); @@ -310,11 +309,13 @@ function shimInit(options: ShimInitOptions = null) { const isUpdate = !!options.destinationResourceId; + const uuid = require('./uuid').default; + if (!(await fs.pathExists(filePath))) throw new Error(_('Cannot access %s', filePath)); defaultProps = defaultProps ? defaultProps : {}; - let resourceId = defaultProps.id ? defaultProps.id : BaseItem.generateUuid(); + let resourceId = defaultProps.id ? defaultProps.id : uuid.create(); if (isUpdate) resourceId = options.destinationResourceId; let resource = isUpdate ? {} : Resource.new(); diff --git a/packages/onenote-converter/.gitignore b/packages/onenote-converter/.gitignore deleted file mode 100644 index e32c5c77238..00000000000 --- a/packages/onenote-converter/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/target -/output - -/.idea -*.iml - -/pkg \ No newline at end of file diff --git a/packages/onenote-converter/.vscode/settings.json b/packages/onenote-converter/.vscode/settings.json deleted file mode 100644 index 352a6265a0d..00000000000 --- a/packages/onenote-converter/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rust-analyzer.linkedProjects": [ - "./Cargo.toml" - ] -} \ No newline at end of file diff --git a/packages/onenote-converter/Cargo.lock b/packages/onenote-converter/Cargo.lock deleted file mode 100644 index 46b36e4f30f..00000000000 --- a/packages/onenote-converter/Cargo.lock +++ /dev/null @@ -1,1040 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "approx" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" -dependencies = [ - "num-traits", -] - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "askama" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134" -dependencies = [ - "askama_derive", - "askama_escape", - "askama_shared", -] - -[[package]] -name = "askama_derive" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522" -dependencies = [ - "askama_shared", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "askama_escape" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" - -[[package]] -name = "askama_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d6083ccb191711e9c2b80b22ee24a8381a18524444914c746d4239e21d1afaf" -dependencies = [ - "askama_escape", - "humansize", - "nom", - "num-traits", - "percent-encoding", - "proc-macro2", - "quote", - "serde", - "syn 1.0.109", - "toml", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - -[[package]] -name = "backtrace" -version = "0.3.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "0.19.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" - -[[package]] -name = "cc" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "color-eyre" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f1885697ee8a177096d42f158922251a41973117f6d8a234cee94b9509157b7" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6eee477a4a8a72f4addd4de416eb56d54bc307b284d6601bafdee1f4ea462d1" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "either" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" - -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enum-primitive-derive" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c375b9c5eadb68d0a6efee2999fef292f45854c3444c86f09d8ab086ba942b0e" -dependencies = [ - "num-traits", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "humansize" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if", - "ryu", - "static_assertions", -] - -[[package]] -name = "libc" -version = "0.2.154" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - -[[package]] -name = "nom" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a7a9657c84d5814c6196b68bb4429df09c18b1573806259fba397ea4ad0d44" -dependencies = [ - "bitvec", - "funty", - "lexical-core", - "memchr", - "version_check", -] - -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "onenote-converter" -version = "0.0.1" -dependencies = [ - "askama", - "bytes", - "color-eyre", - "console_error_panic_hook", - "encoding_rs", - "enum-primitive-derive", - "itertools", - "log", - "mime_guess", - "num-traits", - "once_cell", - "palette", - "paste", - "percent-encoding", - "regex", - "sanitize-filename", - "structopt", - "thiserror", - "uuid", - "wasm-bindgen", - "web-sys", - "widestring", -] - -[[package]] -name = "owo-colors" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" - -[[package]] -name = "palette" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a05c0334468e62a4dfbda34b29110aa7d70d58c7fdb2c9857b5874dd9827cc59" -dependencies = [ - "approx", - "num-traits", - "palette_derive", - "phf", - "phf_codegen", -] - -[[package]] -name = "palette_derive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b4b5f600e60dd3a147fb57b4547033d382d1979eb087af310e91cb45a63b1f4" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom", - "libc", - "rand_chacha", - "rand_core", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core", -] - -[[package]] -name = "regex" -version = "1.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "sanitize-filename" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf18934a12018228c5b55a6dae9df5d0641e3566b3630cb46cc55564068e7c2f" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "serde" -version = "1.0.200" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.200" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "structopt" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d7c0b83d4a500748fa5879461652b361edf5c9d51ede2a2ac03875ca185e24" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", -] - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - -[[package]] -name = "unicode-width" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" - -[[package]] -name = "uuid" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.60", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "widestring" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/packages/onenote-converter/Cargo.toml b/packages/onenote-converter/Cargo.toml deleted file mode 100644 index 4331c3e91ae..00000000000 --- a/packages/onenote-converter/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "onenote-converter" -version = "0.0.1" -authors = ["Pedro Luiz "] -edition = "2018" -description = "Convert Microsoft OneNote® notebooks to HTML" -license = "MIT" -repository = "https://github.com/laurent22/joplin" -keywords = ["onenote"] - -[dependencies] -askama = "0.10" -color-eyre = "0.5" -log = "0.4.11" -mime_guess = "2.0.3" -once_cell = "1.4.1" -palette = "0.5.0" -percent-encoding = "2.1.0" -regex = "1" -sanitize-filename = "0.3.0" -structopt = "0.3" -console_error_panic_hook = "0.1.7" -bytes = "1.2.0" -encoding_rs = "0.8.31" -enum-primitive-derive = "0.2.2" -itertools = "0.10.3" -num-traits = "0.2" -paste = "1.0" -thiserror = "1.0" -uuid = "1.1.2" -widestring = "1.0.2" -wasm-bindgen = "0.2" - -[dependencies.web-sys] -version = "0.3" -features = [ - "console" -] - -[lib] -crate-type = ["cdylib"] \ No newline at end of file diff --git a/packages/onenote-converter/README.md b/packages/onenote-converter/README.md deleted file mode 100644 index fc325889e01..00000000000 --- a/packages/onenote-converter/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# OneNote Converter - -This package is used to process OneNote backup files and output HTML that Joplin can import. - -The code is based on the projects created by https://github.com/msiemens - -We adapted it to target WebAssembly, adding Node.js functions that could interface with the host machine. For that to happen we are using custom-made functions (see `node_functions.js`) and the Node.js standard library (see `src/utils.rs`). - -## How the OneNote Importer Process Works - -The requirement for this project was to simplify the migration process from OneNote to Joplin. The starting point of this migration is to export the notebook from OneNote as a `zip` file containing files in the binary format used by OneNote. - -The process looks like this: - -1. Unzip the backup file. -2. Use `onenote-converter` to read and convert the binary files to HTML (this project). -3. Extract the SVG nodes from the HTML to resources: - 1. Find all SVG nodes in the HTML file. - 2. Create SVG files from the nodes. - 3. Update the HTML file with references to the SVGs. -4. Use the Importer HTML service to create the Joplin notes and resources. - -See the `InteropService_Importer_OneNote` class in the `lib` project for details. - -### SVG Extraction - -The OneNote drawing feature uses `` tags to save user drawings. Joplin doesn't support SVG rendering due to security concerns, so we added a step to extract the `` elements as SVG images, replacing them with `` tags. - -For each HTML file, we: - -- Mount the HTML in the document. -- Find all the `svg` nodes. -- Replace each `svg` node with an `img` node that has a unique title, which will be used as the resource name. -- After editing the entire document, update the HTML. -- Create the SVG images on the local disk with the title used in the replaced `img` tags. - -After this, the HTML should look the same and is ready to be imported by the Importer HTML service. - -## Project structure: - -``` -- onenote-converter - - package.json -> where the project is built - - node_functions.js -> where the custom-made functions used inside rust goes - ... - - pkg -> artifact folder generated in the build step - - onenote_converter.js -> main file - ... - - src - - lib.rs -> starting point -``` - -## Development requirements: - -To work with the project you will need: - -- Rust https://www.rust-lang.org/learn/get-started - -When working with the Rust code you will probably rather run `yarn buildDev` since it is faster and it has more logging messages (they can be disabled in the macro `log!()`) - -During development, it will be easier to test it where this library is called. `InteropService_Importer_Onenote.ts` is the code that depends on this and already has some tests. - -## Security concerns - -We are using WebAssembly with Node.js calls to the file system, reading and writing files and directories, which means -it is not isolated (no more than Node.js is, for that matter). \ No newline at end of file diff --git a/packages/onenote-converter/askama.toml b/packages/onenote-converter/askama.toml deleted file mode 100644 index 50559d54831..00000000000 --- a/packages/onenote-converter/askama.toml +++ /dev/null @@ -1,2 +0,0 @@ -[general] -dirs = ["src/templates"] \ No newline at end of file diff --git a/packages/onenote-converter/assets/icons/License b/packages/onenote-converter/assets/icons/License deleted file mode 100644 index 261eeb9e9f8..00000000000 --- a/packages/onenote-converter/assets/icons/License +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/packages/onenote-converter/assets/icons/arrow-right-line.svg b/packages/onenote-converter/assets/icons/arrow-right-line.svg deleted file mode 100755 index f46779f7337..00000000000 --- a/packages/onenote-converter/assets/icons/arrow-right-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/award-line.svg b/packages/onenote-converter/assets/icons/award-line.svg deleted file mode 100755 index 25849f302b4..00000000000 --- a/packages/onenote-converter/assets/icons/award-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/book-open-line.svg b/packages/onenote-converter/assets/icons/book-open-line.svg deleted file mode 100755 index cbcbbfb9596..00000000000 --- a/packages/onenote-converter/assets/icons/book-open-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/chat-4-line.svg b/packages/onenote-converter/assets/icons/chat-4-line.svg deleted file mode 100755 index c94a0c60efb..00000000000 --- a/packages/onenote-converter/assets/icons/chat-4-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/check-line.svg b/packages/onenote-converter/assets/icons/check-line.svg deleted file mode 100755 index a28368fca94..00000000000 --- a/packages/onenote-converter/assets/icons/check-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/checkbox-blank-circle-fill.svg b/packages/onenote-converter/assets/icons/checkbox-blank-circle-fill.svg deleted file mode 100755 index 5f7ebd1d99c..00000000000 --- a/packages/onenote-converter/assets/icons/checkbox-blank-circle-fill.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/checkbox-blank-circle-line.svg b/packages/onenote-converter/assets/icons/checkbox-blank-circle-line.svg deleted file mode 100755 index 9e627e944be..00000000000 --- a/packages/onenote-converter/assets/icons/checkbox-blank-circle-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/checkbox-blank-fill.svg b/packages/onenote-converter/assets/icons/checkbox-blank-fill.svg deleted file mode 100755 index 30364974fff..00000000000 --- a/packages/onenote-converter/assets/icons/checkbox-blank-fill.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/checkbox-blank-line.svg b/packages/onenote-converter/assets/icons/checkbox-blank-line.svg deleted file mode 100755 index c56cacf082b..00000000000 --- a/packages/onenote-converter/assets/icons/checkbox-blank-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/checkbox-fill.svg b/packages/onenote-converter/assets/icons/checkbox-fill.svg deleted file mode 100755 index 5c439dbf306..00000000000 --- a/packages/onenote-converter/assets/icons/checkbox-fill.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/contacts-line.svg b/packages/onenote-converter/assets/icons/contacts-line.svg deleted file mode 100755 index 6856442df01..00000000000 --- a/packages/onenote-converter/assets/icons/contacts-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/error-warning-line.svg b/packages/onenote-converter/assets/icons/error-warning-line.svg deleted file mode 100755 index 1df56a6c0bd..00000000000 --- a/packages/onenote-converter/assets/icons/error-warning-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/file-list-2-line.svg b/packages/onenote-converter/assets/icons/file-list-2-line.svg deleted file mode 100755 index 0242aa78408..00000000000 --- a/packages/onenote-converter/assets/icons/file-list-2-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/film-line.svg b/packages/onenote-converter/assets/icons/film-line.svg deleted file mode 100755 index 868b3f3fbb6..00000000000 --- a/packages/onenote-converter/assets/icons/film-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/flag-fill.svg b/packages/onenote-converter/assets/icons/flag-fill.svg deleted file mode 100755 index 0a1f84f6853..00000000000 --- a/packages/onenote-converter/assets/icons/flag-fill.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/home-4-line.svg b/packages/onenote-converter/assets/icons/home-4-line.svg deleted file mode 100755 index a799b6ace49..00000000000 --- a/packages/onenote-converter/assets/icons/home-4-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/lightbulb-line.svg b/packages/onenote-converter/assets/icons/lightbulb-line.svg deleted file mode 100755 index fe10f634ca7..00000000000 --- a/packages/onenote-converter/assets/icons/lightbulb-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/link.svg b/packages/onenote-converter/assets/icons/link.svg deleted file mode 100755 index 3b7c8e0697e..00000000000 --- a/packages/onenote-converter/assets/icons/link.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/lock-line.svg b/packages/onenote-converter/assets/icons/lock-line.svg deleted file mode 100755 index c9448583773..00000000000 --- a/packages/onenote-converter/assets/icons/lock-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/mark-pen-line.svg b/packages/onenote-converter/assets/icons/mark-pen-line.svg deleted file mode 100755 index 7f742b4a081..00000000000 --- a/packages/onenote-converter/assets/icons/mark-pen-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/music-fill.svg b/packages/onenote-converter/assets/icons/music-fill.svg deleted file mode 100755 index f0d21411eb9..00000000000 --- a/packages/onenote-converter/assets/icons/music-fill.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/phone-line.svg b/packages/onenote-converter/assets/icons/phone-line.svg deleted file mode 100755 index 2719ef9765d..00000000000 --- a/packages/onenote-converter/assets/icons/phone-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/question-mark.svg b/packages/onenote-converter/assets/icons/question-mark.svg deleted file mode 100755 index 487fcd68470..00000000000 --- a/packages/onenote-converter/assets/icons/question-mark.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/send-plane-2-line.svg b/packages/onenote-converter/assets/icons/send-plane-2-line.svg deleted file mode 100755 index fabf7f23ad1..00000000000 --- a/packages/onenote-converter/assets/icons/send-plane-2-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/assets/icons/star-fill.svg b/packages/onenote-converter/assets/icons/star-fill.svg deleted file mode 100644 index 2d59353112d..00000000000 --- a/packages/onenote-converter/assets/icons/star-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/onenote-converter/assets/icons/user-line.svg b/packages/onenote-converter/assets/icons/user-line.svg deleted file mode 100755 index 9e64bb5632c..00000000000 --- a/packages/onenote-converter/assets/icons/user-line.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/onenote-converter/build.js b/packages/onenote-converter/build.js deleted file mode 100644 index 7684a8255bb..00000000000 --- a/packages/onenote-converter/build.js +++ /dev/null @@ -1,23 +0,0 @@ -const { execCommand } = require('@joplin/utils'); -const yargs = require('yargs'); - -async function main() { - const argv = yargs.argv; - if (!argv.profile) throw new Error('OneNote build: profile value is missing'); - if (!['release', 'dev'].includes(argv.profile)) throw new Error('OneNote build: profile value is invalid'); - - const buildCommand = `wasm-pack build --target nodejs --${argv.profile}`; - - await execCommand(buildCommand); -} - -// eslint-disable-next-line promise/prefer-await-to-then -main().catch((error) => { - console.error('Fatal error'); - if (error.stderr.includes('No such file or directory (os error 2)')) { - console.error('----------------------------------------------------------------'); - console.error('Rust toolchain is missing, please install it: https://rustup.rs/'); - console.error('----------------------------------------------------------------'); - } - process.exit(1); -}); diff --git a/packages/onenote-converter/deny.toml b/packages/onenote-converter/deny.toml deleted file mode 100644 index 40061b126d5..00000000000 --- a/packages/onenote-converter/deny.toml +++ /dev/null @@ -1,22 +0,0 @@ -[advisories] -vulnerability = "deny" -unmaintained = "warn" -yanked = "warn" -notice = "deny" - -[licenses] -unlicensed = "deny" -allow-osi-fsf-free = "either" -copyleft = "allow" -default = "deny" - -[bans] -multiple-versions = "deny" -wildcards = "warn" -skip = [ - { name = "cfg-if" }, -] - -[sources] -unknown-registry = "deny" -unknown-git = "deny" diff --git a/packages/onenote-converter/node_functions.js b/packages/onenote-converter/node_functions.js deleted file mode 100644 index b0bb47914c7..00000000000 --- a/packages/onenote-converter/node_functions.js +++ /dev/null @@ -1,49 +0,0 @@ - -const fs = require('node:fs'); -const path = require('node:path'); - -function mkdirSyncRecursive(filepath) { - if (!fs.existsSync(filepath)) { - mkdirSyncRecursive(filepath.substring(0, filepath.lastIndexOf(path.sep))); - fs.mkdirSync(filepath); - } -} - -function isDirectory(filepath) { - if (!fs.existsSync(filepath)) return false; - return fs.lstatSync(filepath).isDirectory(); -} - -function readDir(filepath) { - const dirContents = fs.readdirSync(filepath, { withFileTypes: true }); - return dirContents.map(entry => filepath + path.sep + entry.name).join('\n'); -} - -function removePrefix(basePath, prefix) { - return basePath.replace(prefix, ''); -} - -function getOutputPath(inputDir, outputDir, filePath) { - const basePathFromInputFolder = filePath.replace(inputDir, ''); - const newOutput = path.join(outputDir, basePathFromInputFolder); - return path.dirname(newOutput); -} - -function getParentDir(filePath) { - return path.basename(path.dirname(filePath)); -} - -function normalizeAndWriteFile(filePath, data) { - filePath = path.normalize(filePath); - fs.writeFileSync(filePath, data); -} - -module.exports = { - mkdirSyncRecursive, - isDirectory, - readDir, - removePrefix, - getOutputPath, - getParentDir, - normalizeAndWriteFile, -}; diff --git a/packages/onenote-converter/package.json b/packages/onenote-converter/package.json deleted file mode 100644 index af37fedfc04..00000000000 --- a/packages/onenote-converter/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "@joplin/onenote-converter", - "collaborators": [ - "Pedro Luiz " - ], - "description": "This package file only exists to build the @joplin/onenote-converter", - "version": "0.0.1", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/laurent22/joplin" - }, - "files": [ - "./pkg/onenote_converter_bg.wasm", - "./pkg/onenote_converter.js", - "./pkg/onenote_converter.d.ts" - ], - "main": "./pkg/onenote_converter.js", - "types": "./pkg/onenote_converter.d.ts", - "scripts": { - "build": "node ./build.js --profile=release", - "buildDev": "node ./build.js --profile=dev" - }, - "devDependencies": { - "wasm-pack": "0.13.0", - "yargs": "17.7.2" - } -} diff --git a/packages/onenote-converter/src/lib.rs b/packages/onenote-converter/src/lib.rs deleted file mode 100644 index 3dc7a512110..00000000000 --- a/packages/onenote-converter/src/lib.rs +++ /dev/null @@ -1,87 +0,0 @@ -pub use crate::parser::Parser; -use color_eyre::eyre::eyre; -use color_eyre::eyre::Result; -use std::panic; -use wasm_bindgen::prelude::wasm_bindgen; - -use crate::utils::utils::{log, log_warn}; -use crate::utils::{get_file_extension, get_file_name, get_output_path, get_parent_dir}; - -mod notebook; -mod page; -mod parser; -mod section; -mod templates; -mod utils; - -extern crate console_error_panic_hook; -extern crate web_sys; - -#[wasm_bindgen] -#[allow(non_snake_case)] -pub fn oneNoteConverter(input: &str, output: &str, base_path: &str) { - panic::set_hook(Box::new(console_error_panic_hook::hook)); - - if let Err(e) = _main(input, output, base_path) { - log_warn!("{:?}", e); - } -} - -fn _main(input_path: &str, output_dir: &str, base_path: &str) -> Result<()> { - log!("Starting parsing of the file: {:?}", input_path); - convert(&input_path, &output_dir, base_path)?; - - Ok(()) -} - -pub fn convert(path: &str, output_dir: &str, base_path: &str) -> Result<()> { - let mut parser = Parser::new(); - - let extension: String = unsafe { get_file_extension(path) } - .unwrap() - .as_string() - .unwrap(); - - match extension.as_str() { - ".one" => { - let _name: String = unsafe { get_file_name(path) }.unwrap().as_string().unwrap(); - log!("Parsing .one file: {}", _name); - - if path.contains("OneNote_RecycleBin") { - return Ok(()); - } - - let section = parser.parse_section(path.to_owned())?; - - let section_output_dir = unsafe { get_output_path(base_path, output_dir, path) } - .unwrap() - .as_string() - .unwrap(); - - section::Renderer::new().render(§ion, section_output_dir.to_owned())?; - } - ".onetoc2" => { - let _name: String = unsafe { get_file_name(path) }.unwrap().as_string().unwrap(); - log!("Parsing .onetoc2 file: {}", _name); - - let notebook = parser.parse_notebook(path.to_owned())?; - - let notebook_name = unsafe { get_parent_dir(path) } - .expect("Input file has no parent folder") - .as_string() - .expect("Parent folder has no name"); - log!("notebook name: {:?}", notebook_name); - - let notebook_output_dir = unsafe { get_output_path(base_path, output_dir, path) } - .unwrap() - .as_string() - .unwrap(); - log!("Notebok directory: {:?}", notebook_output_dir); - - notebook::Renderer::new().render(¬ebook, ¬ebook_name, ¬ebook_output_dir)?; - } - ext => return Err(eyre!("Invalid file extension: {}, file: {}", ext, path)), - } - - Ok(()) -} diff --git a/packages/onenote-converter/src/notebook.rs b/packages/onenote-converter/src/notebook.rs deleted file mode 100644 index 82ab8cf252b..00000000000 --- a/packages/onenote-converter/src/notebook.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::parser::notebook::Notebook; -use crate::parser::property::common::Color; -use crate::parser::section::{Section, SectionEntry}; -use crate::templates::notebook::Toc; -use crate::utils::utils::log; -use crate::utils::{join_path, make_dir, remove_prefix}; -use crate::{section, templates}; -use color_eyre::eyre::Result; -use palette::rgb::Rgb; -use palette::{Alpha, ConvertFrom, Hsl, Saturate, Shade, Srgb}; - -pub(crate) type RgbColor = Alpha, f32>; - -pub(crate) struct Renderer; - -impl Renderer { - pub fn new() -> Self { - Renderer - } - - pub fn render(&mut self, notebook: &Notebook, name: &str, output_dir: &str) -> Result<()> { - log!("Notebook name: {:?} {:?}", name, output_dir); - let _ = unsafe { make_dir(output_dir) }; - - // let notebook_dir = unsafe { join_path(output_dir, sanitize_filename::sanitize(name).as_str()) }.unwrap().as_string().unwrap(); - let notebook_dir = output_dir.to_owned(); - - let _ = unsafe { make_dir(¬ebook_dir) }; - - let mut toc = Vec::new(); - - for entry in notebook.entries() { - match entry { - SectionEntry::Section(section) => { - toc.push(Toc::Section(self.render_section( - section, - notebook_dir.clone(), - output_dir.into(), - )?)); - } - SectionEntry::SectionGroup(group) => { - let dir_name = sanitize_filename::sanitize(group.display_name()); - let section_group_dir = - unsafe { join_path(notebook_dir.as_str(), dir_name.as_str()) } - .unwrap() - .as_string() - .unwrap(); - - log!("Section group directory: {:?}", section_group_dir); - let _ = unsafe { make_dir(section_group_dir.as_str()) }; - - let mut entries = Vec::new(); - - for entry in group.entries() { - if let SectionEntry::Section(section) = entry { - entries.push(self.render_section( - section, - section_group_dir.clone(), - output_dir.to_owned(), - )?); - } - } - - toc.push(templates::notebook::Toc::SectionGroup( - group.display_name().to_string(), - entries, - )) - } - } - } - - templates::notebook::render(name, &toc)?; - - Ok(()) - } - - fn render_section( - &mut self, - section: &Section, - notebook_dir: String, - base_dir: String, - ) -> Result { - let mut renderer = section::Renderer::new(); - let section_path = renderer.render(section, notebook_dir)?; - log!("section_path: {:?}", section_path); - - let path_from_base_dir = unsafe { remove_prefix(section_path.as_str(), base_dir.as_str()) } - .unwrap() - .as_string() - .unwrap(); - log!("path_from_base_dir: {:?}", path_from_base_dir); - Ok(templates::notebook::Section { - name: section.display_name().to_string(), - path: path_from_base_dir, - color: section.color().map(prepare_color), - }) - } -} - -fn prepare_color(color: Color) -> RgbColor { - Alpha { - alpha: color.alpha() as f32 / 255.0, - color: Srgb::convert_from( - Hsl::convert_from(Srgb::new( - color.r() as f32 / 255.0, - color.g() as f32 / 255.0, - color.b() as f32 / 255.0, - )) - .darken(0.2) - .saturate(1.0), - ) - .into_format(), - } -} diff --git a/packages/onenote-converter/src/page/content.rs b/packages/onenote-converter/src/page/content.rs deleted file mode 100644 index f9e41dea6ae..00000000000 --- a/packages/onenote-converter/src/page/content.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::page::Renderer; -use color_eyre::Result; -use log::warn; -// use crate::something_else::contents::Content; -use crate::parser::contents::Content; - -impl<'a> Renderer<'a> { - pub(crate) fn render_content(&mut self, content: &Content) -> Result { - match content { - Content::RichText(text) => self.render_rich_text(text), - Content::Image(image) => self.render_image(image), - Content::EmbeddedFile(file) => self.render_embedded_file(file), - Content::Table(table) => self.render_table(table), - Content::Ink(ink) => Ok(self.render_ink(ink, None, false)), - Content::Unknown => { - warn!("Page with unknown content"); - - Ok(String::new()) - } - } - } -} diff --git a/packages/onenote-converter/src/page/embedded_file.rs b/packages/onenote-converter/src/page/embedded_file.rs deleted file mode 100644 index 391e94e653b..00000000000 --- a/packages/onenote-converter/src/page/embedded_file.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::page::Renderer; -use crate::parser::contents::EmbeddedFile; -use crate::parser::property::embedded_file::FileType; -use crate::utils::utils::log; -use crate::utils::{join_path, write_file}; -use color_eyre::eyre::ContextCompat; -use color_eyre::Result; -use std::path::PathBuf; - -impl<'a> Renderer<'a> { - pub(crate) fn render_embedded_file(&mut self, file: &EmbeddedFile) -> Result { - let content; - - let filename = self.determine_filename(file.filename())?; - let path = unsafe { join_path(self.output.as_str(), filename.as_str()) } - .unwrap() - .as_string() - .unwrap(); - log!("Rendering embedded file: {:?}", path); - let _ = unsafe { write_file(path.as_str(), file.data()) }; - - let file_type = Self::guess_type(file); - - match file_type { - FileType::Audio => content = format!("", filename), - FileType::Video => content = format!("", filename), - FileType::Unknown => { - content = format!( - "

    {}

    ", - filename, filename - ) - } - }; - - Ok(self.render_with_note_tags(file.note_tags(), content)) - } - - fn guess_type(file: &EmbeddedFile) -> FileType { - match file.file_type() { - FileType::Audio => return FileType::Audio, - FileType::Video => return FileType::Video, - _ => {} - }; - - let filename = file.filename(); - - if let Some(mime) = mime_guess::from_path(filename).first() { - if mime.type_() == "audio" { - return FileType::Audio; - } - - if mime.type_() == "video" { - return FileType::Video; - } - } - FileType::Unknown - } - - pub(crate) fn determine_filename(&mut self, filename: &str) -> Result { - let mut i = 0; - let mut current_filename = filename.to_string(); - - loop { - if !self.section.files.contains(¤t_filename) { - self.section.files.insert(current_filename.clone()); - - return Ok(current_filename); - } - - let path = PathBuf::from(filename); - let ext = path - .extension() - .wrap_err("Embedded file has no extension")? - .to_str() - .wrap_err("Embedded file name is non utf-8")?; - let base = path - .as_os_str() - .to_str() - .wrap_err("Embedded file name is non utf-8")? - .strip_suffix(ext) - .wrap_err("Failed to strip extension from file name")? - .trim_matches('.'); - - current_filename = format!("{}-{}.{}", base, i, ext); - - i += 1; - } - } -} diff --git a/packages/onenote-converter/src/page/image.rs b/packages/onenote-converter/src/page/image.rs deleted file mode 100644 index 03cf7b4d914..00000000000 --- a/packages/onenote-converter/src/page/image.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::page::Renderer; -use crate::parser::contents::Image; -use crate::utils::utils::log; -use crate::utils::{join_path, px, write_file, AttributeSet, StyleSet}; -use color_eyre::Result; - -impl<'a> Renderer<'a> { - pub(crate) fn render_image(&mut self, image: &Image) -> Result { - let mut content = String::new(); - - if let Some(data) = image.data() { - let filename = self.determine_image_filename(image)?; - let path = unsafe { join_path(self.output.as_str(), filename.as_str()) } - .unwrap() - .as_string() - .unwrap(); - log!("Rendering image: {:?}", path); - let _ = unsafe { write_file(path.as_str(), data) }; - - let mut attrs = AttributeSet::new(); - let mut styles = StyleSet::new(); - - attrs.set("src", filename); - - if let Some(text) = image.alt_text() { - attrs.set("alt", text.to_string().replace('"', """)); - } - - if let Some(width) = image.layout_max_width() { - styles.set("max-width", px(width)); - } - - if let Some(height) = image.layout_max_height() { - styles.set("max-height", px(height)); - } - - if image.offset_horizontal().is_some() || image.offset_vertical().is_some() { - styles.set("position", "absolute".to_string()); - } - - if let Some(offset) = image.offset_horizontal() { - styles.set("left", px(offset)); - } - - if let Some(offset) = image.offset_vertical() { - styles.set("top", px(offset)); - } - - if styles.len() > 0 { - attrs.set("style", styles.to_string()); - } - - content.push_str(&format!("", attrs.to_string())); - } - - Ok(self.render_with_note_tags(image.note_tags(), content)) - } - - fn determine_image_filename(&mut self, image: &Image) -> Result { - if let Some(name) = image.image_filename() { - return self.determine_filename(name); - } - - if let Some(ext) = image.extension() { - let mut i = 0; - - loop { - let filename = format!("image{}{}", i, ext); - - if !self.section.files.contains(&filename) { - self.section.files.insert(filename.clone()); - - return Ok(filename); - } - - i += 1; - } - } - - unimplemented!() - } -} diff --git a/packages/onenote-converter/src/page/ink.rs b/packages/onenote-converter/src/page/ink.rs deleted file mode 100644 index 0ccd9ab21ad..00000000000 --- a/packages/onenote-converter/src/page/ink.rs +++ /dev/null @@ -1,210 +0,0 @@ -use crate::page::Renderer; -use crate::parser::contents::{Ink, InkBoundingBox, InkPoint, InkStroke}; -use crate::utils::{px, AttributeSet, StyleSet}; -use itertools::Itertools; - -impl<'a> Renderer<'a> { - const SVG_SCALING_FACTOR: f32 = 2540.0 / 96.0; - - pub(crate) fn render_ink( - &mut self, - ink: &Ink, - display_bounding_box: Option<&InkBoundingBox>, - embedded: bool, - ) -> String { - if ink.ink_strokes().is_empty() { - return String::new(); - } - - let mut attrs = AttributeSet::new(); - let mut styles = StyleSet::new(); - - styles.set("overflow", "visible".to_string()); - styles.set("position", "absolute".to_string()); - - let path = self.render_ink_path(ink.ink_strokes()); - - let offset_horizontal = ink - .offset_horizontal() - .filter(|_| !embedded) - .unwrap_or_default(); - let offset_vertical = ink - .offset_vertical() - .filter(|_| !embedded) - .unwrap_or_default(); - - let display_bounding_box = ink - .bounding_box() - .or_else(|| display_bounding_box.map(|bb| bb.scale(Self::SVG_SCALING_FACTOR))) - .filter(|_| embedded); - - let (x_min, width) = get_boundary(ink.ink_strokes(), |p| p.x()); - let (y_min, height) = get_boundary(ink.ink_strokes(), |p| p.y()); - - let stroke_strength = ink.ink_strokes()[0] - .width() - .max(ink.ink_strokes()[0].height()) - .max(140.0); - - let x_min = x_min as f32 - stroke_strength / 2.0; - let y_min = y_min as f32 - stroke_strength / 2.0; - - let width = width as f32 + stroke_strength + Self::SVG_SCALING_FACTOR; - let height = height as f32 + stroke_strength + Self::SVG_SCALING_FACTOR; - - styles.set( - "height", - format!( - "{}px", - ((height as f32) / (Self::SVG_SCALING_FACTOR)).round() - ), - ); - styles.set( - "width", - format!( - "{}px", - ((width as f32) / (Self::SVG_SCALING_FACTOR)).round() - ), - ); - - let display_y_min = display_bounding_box.map(|bb| bb.y()).unwrap_or_default(); - let display_x_min = display_bounding_box.map(|bb| bb.x()).unwrap_or_default(); - - styles.set( - "top", - format!( - "{}px", - ((y_min - display_y_min) / Self::SVG_SCALING_FACTOR + offset_vertical * 48.0) - .round() - ), - ); - styles.set( - "left", - format!( - "{}px", - ((x_min - display_x_min) / Self::SVG_SCALING_FACTOR + offset_horizontal * 48.0) - .round() - ), - ); - - attrs.set( - "viewBox", - format!( - "{} {} {} {}", - x_min.round(), - y_min.round(), - width.round(), - height.round() - ), - ); - - if styles.len() > 0 { - attrs.set("style", styles.to_string()); - } - - if embedded { - let mut span_styles = StyleSet::new(); - - if let Some(bb) = display_bounding_box { - span_styles.set("width", px(bb.width() / Self::SVG_SCALING_FACTOR / 48.0)); - span_styles.set("height", px(bb.height() / Self::SVG_SCALING_FACTOR / 48.0)); - } - - format!( - "{}", - span_styles.to_string(), - attrs.to_string(), - path - ) - } else { - format!("{}", attrs.to_string(), path) - } - } - - fn render_ink_path(&mut self, strokes: &[InkStroke]) -> String { - let mut attrs = AttributeSet::new(); - - attrs.set( - "d", - strokes - .iter() - .map(|stroke| self.render_ink_path_points(stroke)) - .collect_vec() - .join(" "), - ); - - let stroke = &strokes[0]; - - let opacity = (255 - stroke.transparency().unwrap_or_default()) as f32 / 256.0; - attrs.set("opacity", format!("{:.2}", opacity)); - - let color = if let Some(value) = stroke.color() { - let r = value % 256; - - let rem = (value - r) / 256; - let g = rem % 256; - - let rem = (rem - g) / 256; - let b = rem % 256; - - format!("rgb({}, {}, {})", r, g, b) - } else { - "WindowText".to_string() - }; - attrs.set("stroke", color); - - attrs.set("stroke-width", stroke.width().round().to_string()); - - let pen_type = stroke.pen_tip().unwrap_or_default(); - attrs.set( - "stroke-linejoin", - if pen_type == 0 { "round" } else { "bevel" }.to_string(), - ); - attrs.set( - "stroke-linecap", - if pen_type == 0 { "round" } else { "square" }.to_string(), - ); - - attrs.set("fill", "none".to_string()); - - format!("", attrs.to_string()) - } - - fn render_ink_path_points(&self, stroke: &InkStroke) -> String { - let start = &stroke.path()[0]; - let mut path = stroke.path()[1..].iter().map(display_point).collect_vec(); - - if path.is_empty() { - path.push("0 0".to_string()); - } - - format!("M {} l {}", display_point(start), path.join(" ")) - } -} - -fn get_boundary f32>(strokes: &[InkStroke], coord: F) -> (f32, f32) { - let mut min = f32::INFINITY; - let mut max = f32::NEG_INFINITY; - - for stroke in strokes { - let start = coord(&stroke.path()[0]); - let mut pos = start; - - for point in stroke.path()[1..].iter() { - pos += coord(point); - - if pos < min { - min = pos; - } - if pos > max { - max = pos; - } - } - } - - (min, max - min) -} - -fn display_point(p: &InkPoint) -> String { - format!("{} {}", p.x().floor(), p.y().round()) -} diff --git a/packages/onenote-converter/src/page/list.rs b/packages/onenote-converter/src/page/list.rs deleted file mode 100644 index 1cc09355930..00000000000 --- a/packages/onenote-converter/src/page/list.rs +++ /dev/null @@ -1,182 +0,0 @@ -use crate::page::Renderer; -use crate::parser::contents::{List, OutlineElement}; -use crate::parser::property::common::ColorRef; -use crate::utils::{px, AttributeSet, StyleSet}; -use color_eyre::Result; - -const FORMAT_NUMBERED_LIST: char = '\u{fffd}'; - -impl<'a> Renderer<'a> { - pub(crate) fn render_list<'b>( - &mut self, - elements: impl Iterator, - indents: &[f32], - ) -> Result { - let mut contents = String::new(); - let mut in_list = false; - let mut list_end = None; - - for (element, parent_level, current_level) in elements { - if !in_list && self.is_list(element) { - let tags = self.list_tags(element); - let list_start = tags.0; - list_end = Some(tags.1); - - contents.push_str(&list_start); - in_list = true; - } - - if in_list && !self.is_list(element) { - contents.push_str(&list_end.take().expect("no list end tag defined")); - in_list = false; - } - - contents.push_str(&self.render_outline_element( - element, - parent_level, - current_level, - indents, - )?); - } - - if in_list { - contents.push_str(&list_end.expect("no list end tag defined")); - } - - Ok(contents) - } - - pub(crate) fn list_tags(&mut self, element: &OutlineElement) -> (String, String) { - let list = element - .list_contents() - .first() - .expect("no list contents defined"); - - let tag = if self.is_numbered_list(list) { - "ol" - } else { - "ul" - }; - let attrs = self.list_attrs(list, element.list_spacing()); - - (format!("<{} {}>", tag, attrs), format!("", tag)) - } - - fn list_attrs(&mut self, list: &List, spacing: Option) -> AttributeSet { - let mut attrs = AttributeSet::new(); - let mut container_style = StyleSet::new(); - let mut item_style = StyleSet::new(); - let mut marker_style = StyleSet::new(); - - let mut list_font = list.list_font(); - let mut list_format = list.list_format(); - let mut font_size = list.font_size(); - - self.fix_wingdings(&mut list_font, &mut list_format, &mut font_size); - - match list_format { - [FORMAT_NUMBERED_LIST, '\u{0}', ..] => {} - [FORMAT_NUMBERED_LIST, '\u{1}', ..] => { - container_style.set("list-style-type", "upper-roman".to_string()) - } - [FORMAT_NUMBERED_LIST, '\u{2}', ..] => { - container_style.set("list-style-type", "lower-roman".to_string()) - } - [FORMAT_NUMBERED_LIST, '\u{3}', ..] => { - container_style.set("list-style-type", "upper-latin".to_string()) - } - [FORMAT_NUMBERED_LIST, '\u{4}', ..] => { - container_style.set("list-style-type", "lower-latin".to_string()) - } - [FORMAT_NUMBERED_LIST, c, ..] => { - dbg!(c); - unimplemented!(); - } - [c] => marker_style.set("content", format!("'{}'", c)), - _ => {} - } - - let bullet_spacing = spacing.unwrap_or(0.2); - - item_style.set("padding-left", px(bullet_spacing)); - - container_style.set("position", "relative".to_string()); - container_style.set("left", px(-bullet_spacing)); - - if let Some(font) = list_font { - marker_style.set("font-family", font.to_string()); - } - - if let Some(font) = list.font() { - marker_style.set("font-family", font.to_string()); - } - - if let Some(ColorRef::Manual { r, g, b }) = list.font_color() { - marker_style.set("color", format!("rgb({},{},{})", r, g, b)); - } - - if let Some(size) = font_size { - marker_style.set("font-size", ((size as f32) / 2.0).to_string() + "pt"); - } - - if let Some(restart) = list.list_restart() { - attrs.set("start", restart.to_string()) - } - - if container_style.len() > 0 { - attrs.set("style", container_style.to_string()); - } - - let class = self.gen_class("list"); - - if marker_style.len() > 0 { - attrs.set("class", class.clone()); - - self.global_styles - .insert(format!(".{} li::marker", class), marker_style); - } - - self.global_styles - .insert(format!(".{} li", class), item_style); - - attrs - } - - fn fix_wingdings( - &self, - list_font: &mut Option<&str>, - list_format: &mut &[char], - font_size: &mut Option, - ) { - match list_font.zip(list_format.first()) { - // See http://www.alanwood.net/demos/wingdings.html - Some(("Wingdings", '\u{a7}')) => *list_format = &['\u{25aa}'], - Some(("Wingdings", '\u{a8}')) => *list_format = &['\u{25fb}'], - Some(("Wingdings", '\u{77}')) => *list_format = &['\u{2b25}'], - - // See http://www.alanwood.net/demos/wingdings-2.html - Some(("Wingdings 2", '\u{ae}')) => *list_format = &['\u{25c6}'], - - // See http://www.alanwood.net/demos/wingdings-3.html - Some(("Wingdings 3", '\u{7d}')) => { - *list_format = &['\u{25b6}']; - *font_size = Some(18); - } - - _ => return, - } - - *list_font = Some("Calibri"); - } - - fn is_numbered_list(&self, list: &List) -> bool { - list.list_format() - .first() - .map(|c| *c == FORMAT_NUMBERED_LIST) - .unwrap_or_default() - } - - pub(crate) fn is_list(&self, element: &OutlineElement) -> bool { - element.list_contents().first().is_some() - } -} diff --git a/packages/onenote-converter/src/page/mod.rs b/packages/onenote-converter/src/page/mod.rs deleted file mode 100644 index e66571e9107..00000000000 --- a/packages/onenote-converter/src/page/mod.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::parser::page::{Page, PageContent}; -use crate::section; -use crate::utils::StyleSet; -use color_eyre::Result; -use std::collections::{HashMap, HashSet}; - -pub(crate) mod content; -pub(crate) mod embedded_file; -pub(crate) mod image; -pub(crate) mod ink; -pub(crate) mod list; -pub(crate) mod note_tag; -pub(crate) mod outline; -pub(crate) mod rich_text; -pub(crate) mod table; - -pub(crate) struct Renderer<'a> { - output: String, - section: &'a mut section::Renderer, - - in_list: bool, - global_styles: HashMap, - global_classes: HashSet, -} - -impl<'a> Renderer<'a> { - pub(crate) fn new(output: String, section: &'a mut section::Renderer) -> Self { - Self { - output, - section, - in_list: false, - global_styles: HashMap::new(), - global_classes: HashSet::new(), - } - } - - pub(crate) fn render_page(&mut self, page: &Page) -> Result { - let title_text = page.title_text().unwrap_or("Untitled Page"); - - let mut content = String::new(); - - if let Some(title) = page.title() { - let mut styles = StyleSet::new(); - styles.set("position", "absolute".to_string()); - styles.set( - "top", - format!("{}px", (title.offset_vertical() * 48.0 + 24.0).round()), - ); - styles.set( - "left", - format!("{}px", (title.offset_horizontal() * 48.0 + 48.0).round()), - ); - - let mut title_field = format!("
    ", styles.to_string()); - - for outline in title.contents() { - title_field.push_str(&self.render_outline(outline)?) - } - - title_field.push_str("
    "); - - content.push_str(&title_field); - } - - let page_content = page - .contents() - .iter() - .map(|content| self.render_page_content(content)) - .collect::>()?; - - content.push_str(&page_content); - - crate::templates::page::render(title_text, &content, &self.global_styles) - } - - pub(crate) fn gen_class(&mut self, prefix: &str) -> String { - let mut i = 0; - - loop { - let class = format!("{}-{}", prefix, i); - if !self.global_classes.contains(&class) { - self.global_classes.insert(class.clone()); - - return class; - } - - i += 1; - } - } - - fn render_page_content(&mut self, content: &PageContent) -> Result { - match content { - PageContent::Outline(outline) => self.render_outline(outline), - PageContent::Image(image) => self.render_image(image), - PageContent::EmbeddedFile(file) => self.render_embedded_file(file), - PageContent::Ink(ink) => Ok(self.render_ink(ink, None, false)), - PageContent::Unknown => Ok(String::new()), - } - } -} diff --git a/packages/onenote-converter/src/page/note_tag.rs b/packages/onenote-converter/src/page/note_tag.rs deleted file mode 100644 index da88b47b42c..00000000000 --- a/packages/onenote-converter/src/page/note_tag.rs +++ /dev/null @@ -1,539 +0,0 @@ -use crate::page::Renderer; -use crate::parser::contents::{NoteTag, OutlineElement}; -use crate::parser::property::common::ColorRef; -use crate::parser::property::note_tag::{ActionItemStatus, NoteTagShape}; -use crate::utils::StyleSet; -use std::borrow::Cow; - -const COLOR_BLUE: &str = "#4673b7"; -const COLOR_GREEN: &str = "#369950"; -const COLOR_ORANGE: &str = "#dba24d"; -const COLOR_PINK: &str = "#f78b9d"; -const COLOR_RED: &str = "#db5b4d"; -const COLOR_YELLOW: &str = "#ffd678"; - -const ICON_ARROW_RIGHT: &str = include_str!("../../assets/icons/arrow-right-line.svg"); -const ICON_AWARD: &str = include_str!("../../assets/icons/award-line.svg"); -const ICON_BOOK: &str = include_str!("../../assets/icons/book-open-line.svg"); -const ICON_BUBBLE: &str = include_str!("../../assets/icons/chat-4-line.svg"); -const ICON_CHECKBOX_COMPLETE: &str = include_str!("../../assets/icons/checkbox-fill.svg"); -const ICON_CHECKBOX_EMPTY: &str = include_str!("../../assets/icons/checkbox-blank-line.svg"); -const ICON_CHECK_MARK: &str = include_str!("../../assets/icons/check-line.svg"); -const ICON_CIRCLE: &str = include_str!("../../assets/icons/checkbox-blank-circle-fill.svg"); -const ICON_CONTACT: &str = include_str!("../../assets/icons/contacts-line.svg"); -const ICON_EMAIL: &str = include_str!("../../assets/icons/send-plane-2-line.svg"); -const ICON_ERROR: &str = include_str!("../../assets/icons/error-warning-line.svg"); -const ICON_FILM: &str = include_str!("../../assets/icons/film-line.svg"); -const ICON_FLAG: &str = include_str!("../../assets/icons/flag-fill.svg"); -const ICON_HOME: &str = include_str!("../../assets/icons/home-4-line.svg"); -const ICON_LIGHT_BULB: &str = include_str!("../../assets/icons/lightbulb-line.svg"); -const ICON_LINK: &str = include_str!("../../assets/icons/link.svg"); -const ICON_LOCK: &str = include_str!("../../assets/icons/lock-line.svg"); -const ICON_MUSIC: &str = include_str!("../../assets/icons/music-fill.svg"); -const ICON_PAPER: &str = include_str!("../../assets/icons/file-list-2-line.svg"); -const ICON_PEN: &str = include_str!("../../assets/icons/mark-pen-line.svg"); -const ICON_PERSON: &str = include_str!("../../assets/icons/user-line.svg"); -const ICON_PHONE: &str = include_str!("../../assets/icons/phone-line.svg"); -const ICON_QUESTION_MARK: &str = include_str!("../../assets/icons/question-mark.svg"); -const ICON_SQUARE: &str = include_str!("../../assets/icons/checkbox-blank-fill.svg"); -const ICON_STAR: &str = include_str!("../../assets/icons/star-fill.svg"); - -#[derive(Debug, Copy, Clone, PartialEq)] -enum IconSize { - Normal, - Large, -} - -impl<'a> Renderer<'a> { - pub(crate) fn render_with_note_tags( - &mut self, - note_tags: &[NoteTag], - content: String, - ) -> String { - if let Some((markup, styles)) = self.render_note_tags(note_tags) { - let mut contents = String::new(); - contents.push_str(&format!("
    {}", styles, markup)); - contents.push_str(&content); - contents.push_str("
    "); - - contents - } else { - content - } - } - - pub(crate) fn render_note_tags(&mut self, note_tags: &[NoteTag]) -> Option<(String, StyleSet)> { - let mut markup = String::new(); - let mut styles = StyleSet::new(); - - if note_tags.is_empty() { - return None; - } - - for note_tag in note_tags { - if let Some(def) = note_tag.definition() { - if let Some(ColorRef::Manual { r, g, b }) = def.highlight_color() { - styles.set("background-color", format!("rgb({},{},{})", r, g, b)); - } - - if let Some(ColorRef::Manual { r, g, b }) = def.text_color() { - styles.set("color", format!("rgb({},{},{})", r, g, b)); - } - - if def.shape() != NoteTagShape::NoIcon { - let (icon, icon_style) = - self.note_tag_icon(def.shape(), note_tag.item_status()); - let mut icon_classes = vec!["note-tag-icon".to_string()]; - - if icon_style.len() > 0 { - let class = self.gen_class("icon"); - icon_classes.push(class.to_string()); - - self.global_styles - .insert(format!(".{} > svg", class), icon_style); - } - - markup.push_str(&format!( - "{}", - icon_classes.join(" "), - icon - )); - } - } - } - - Some((markup, styles)) - } - - pub(crate) fn has_note_tag(&self, element: &OutlineElement) -> bool { - element - .contents() - .iter() - .flat_map(|element| element.rich_text()) - .any(|text| !text.note_tags().is_empty()) - } - - fn note_tag_icon( - &self, - shape: NoteTagShape, - status: ActionItemStatus, - ) -> (Cow<'static, str>, StyleSet) { - let mut style = StyleSet::new(); - - match shape { - NoteTagShape::NoIcon => unimplemented!(), - NoteTagShape::GreenCheckBox => self.icon_checkbox(status, style, COLOR_GREEN), - NoteTagShape::YellowCheckBox => self.icon_checkbox(status, style, COLOR_YELLOW), - NoteTagShape::BlueCheckBox => self.icon_checkbox(status, style, COLOR_BLUE), - NoteTagShape::GreenStarCheckBox => { - self.icon_checkbox_with_star(status, style, COLOR_GREEN) - } - NoteTagShape::YellowStarCheckBox => { - self.icon_checkbox_with_star(status, style, COLOR_YELLOW) - } - NoteTagShape::BlueStarCheckBox => { - self.icon_checkbox_with_star(status, style, COLOR_BLUE) - } - NoteTagShape::GreenExclamationCheckBox => { - self.icon_checkbox_with_exclamation(status, style, COLOR_GREEN) - } - NoteTagShape::YellowExclamationCheckBox => { - self.icon_checkbox_with_exclamation(status, style, COLOR_YELLOW) - } - NoteTagShape::BlueExclamationCheckBox => { - self.icon_checkbox_with_exclamation(status, style, COLOR_BLUE) - } - NoteTagShape::GreenRightArrowCheckBox => { - self.icon_checkbox_with_right_arrow(status, style, COLOR_GREEN) - } - NoteTagShape::YellowRightArrowCheckBox => { - self.icon_checkbox_with_right_arrow(status, style, COLOR_YELLOW) - } - NoteTagShape::BlueRightArrowCheckBox => { - self.icon_checkbox_with_right_arrow(status, style, COLOR_BLUE) - } - NoteTagShape::YellowStar => { - style.set("fill", COLOR_YELLOW.to_string()); - - ( - Cow::from(ICON_STAR), - self.icon_style(IconSize::Normal, style), - ) - } - NoteTagShape::BlueFollowUpFlag => unimplemented!(), - NoteTagShape::QuestionMark => ( - Cow::from(ICON_QUESTION_MARK), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::BlueRightArrow => unimplemented!(), - NoteTagShape::HighPriority => ( - Cow::from(ICON_ERROR), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::ContactInformation => ( - Cow::from(ICON_PHONE), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::Meeting => unimplemented!(), - NoteTagShape::TimeSensitive => unimplemented!(), - NoteTagShape::LightBulb => ( - Cow::from(ICON_LIGHT_BULB), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::Pushpin => unimplemented!(), - NoteTagShape::Home => ( - Cow::from(ICON_HOME), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::CommentBubble => ( - Cow::from(ICON_BUBBLE), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::SmilingFace => unimplemented!(), - NoteTagShape::AwardRibbon => ( - Cow::from(ICON_AWARD), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::YellowKey => unimplemented!(), - NoteTagShape::BlueCheckBox1 => self.icon_checkbox_with_1(status, style, COLOR_BLUE), - NoteTagShape::BlueCircle1 => unimplemented!(), - NoteTagShape::BlueCheckBox2 => self.icon_checkbox_with_2(status, style, COLOR_BLUE), - NoteTagShape::BlueCircle2 => unimplemented!(), - NoteTagShape::BlueCheckBox3 => self.icon_checkbox_with_3(status, style, COLOR_BLUE), - NoteTagShape::BlueCircle3 => unimplemented!(), - NoteTagShape::BlueEightPointStar => unimplemented!(), - NoteTagShape::BlueCheckMark => self.icon_checkmark(style, COLOR_BLUE), - NoteTagShape::BlueCircle => self.icon_circle(style, COLOR_BLUE), - NoteTagShape::BlueDownArrow => unimplemented!(), - NoteTagShape::BlueLeftArrow => unimplemented!(), - NoteTagShape::BlueSolidTarget => unimplemented!(), - NoteTagShape::BlueStar => unimplemented!(), - NoteTagShape::BlueSun => unimplemented!(), - NoteTagShape::BlueTarget => unimplemented!(), - NoteTagShape::BlueTriangle => unimplemented!(), - NoteTagShape::BlueUmbrella => unimplemented!(), - NoteTagShape::BlueUpArrow => unimplemented!(), - NoteTagShape::BlueXWithDots => unimplemented!(), - NoteTagShape::BlueX => unimplemented!(), - NoteTagShape::GreenCheckBox1 => self.icon_checkbox_with_1(status, style, COLOR_GREEN), - NoteTagShape::GreenCircle1 => unimplemented!(), - NoteTagShape::GreenCheckBox2 => self.icon_checkbox_with_2(status, style, COLOR_GREEN), - NoteTagShape::GreenCircle2 => unimplemented!(), - NoteTagShape::GreenCheckBox3 => self.icon_checkbox_with_3(status, style, COLOR_GREEN), - NoteTagShape::GreenCircle3 => unimplemented!(), - NoteTagShape::GreenEightPointStar => unimplemented!(), - NoteTagShape::GreenCheckMark => self.icon_checkmark(style, COLOR_GREEN), - NoteTagShape::GreenCircle => self.icon_circle(style, COLOR_GREEN), - NoteTagShape::GreenDownArrow => unimplemented!(), - NoteTagShape::GreenLeftArrow => unimplemented!(), - NoteTagShape::GreenRightArrow => unimplemented!(), - NoteTagShape::GreenSolidArrow => unimplemented!(), - NoteTagShape::GreenStar => unimplemented!(), - NoteTagShape::GreenSun => unimplemented!(), - NoteTagShape::GreenTarget => unimplemented!(), - NoteTagShape::GreenTriangle => unimplemented!(), - NoteTagShape::GreenUmbrella => unimplemented!(), - NoteTagShape::GreenUpArrow => unimplemented!(), - NoteTagShape::GreenXWithDots => unimplemented!(), - NoteTagShape::GreenX => unimplemented!(), - NoteTagShape::YellowCheckBox1 => self.icon_checkbox_with_1(status, style, COLOR_YELLOW), - NoteTagShape::YellowCircle1 => unimplemented!(), - NoteTagShape::YellowCheckBox2 => self.icon_checkbox_with_2(status, style, COLOR_YELLOW), - NoteTagShape::YellowCircle2 => unimplemented!(), - NoteTagShape::YellowCheckBox3 => self.icon_checkbox_with_3(status, style, COLOR_YELLOW), - NoteTagShape::YellowCircle3 => unimplemented!(), - NoteTagShape::YellowEightPointStar => unimplemented!(), - NoteTagShape::YellowCheckMark => self.icon_checkmark(style, COLOR_YELLOW), - NoteTagShape::YellowCircle => self.icon_circle(style, COLOR_YELLOW), - NoteTagShape::YellowDownArrow => unimplemented!(), - NoteTagShape::YellowLeftArrow => unimplemented!(), - NoteTagShape::YellowRightArrow => unimplemented!(), - NoteTagShape::YellowSolidTarget => unimplemented!(), - NoteTagShape::YellowSun => unimplemented!(), - NoteTagShape::YellowTarget => unimplemented!(), - NoteTagShape::YellowTriangle => unimplemented!(), - NoteTagShape::YellowUmbrella => unimplemented!(), - NoteTagShape::YellowUpArrow => unimplemented!(), - NoteTagShape::YellowXWithDots => unimplemented!(), - NoteTagShape::YellowX => unimplemented!(), - NoteTagShape::FollowUpTodayFlag => unimplemented!(), - NoteTagShape::FollowUpTomorrowFlag => unimplemented!(), - NoteTagShape::FollowUpThisWeekFlag => unimplemented!(), - NoteTagShape::FollowUpNextWeekFlag => unimplemented!(), - NoteTagShape::NoFollowUpDateFlag => unimplemented!(), - NoteTagShape::BluePersonCheckBox => { - self.icon_checkbox_with_person(status, style, COLOR_BLUE) - } - NoteTagShape::YellowPersonCheckBox => { - self.icon_checkbox_with_person(status, style, COLOR_YELLOW) - } - NoteTagShape::GreenPersonCheckBox => { - self.icon_checkbox_with_person(status, style, COLOR_GREEN) - } - NoteTagShape::BlueFlagCheckBox => { - self.icon_checkbox_with_flag(status, style, COLOR_BLUE) - } - NoteTagShape::RedFlagCheckBox => self.icon_checkbox_with_flag(status, style, COLOR_RED), - NoteTagShape::GreenFlagCheckBox => { - self.icon_checkbox_with_flag(status, style, COLOR_GREEN) - } - NoteTagShape::RedSquare => self.icon_square(style, COLOR_RED), - NoteTagShape::YellowSquare => self.icon_square(style, COLOR_YELLOW), - NoteTagShape::BlueSquare => self.icon_square(style, COLOR_BLUE), - NoteTagShape::GreenSquare => self.icon_square(style, COLOR_GREEN), - NoteTagShape::OrangeSquare => self.icon_square(style, COLOR_ORANGE), - NoteTagShape::PinkSquare => self.icon_square(style, COLOR_PINK), - NoteTagShape::EMailMessage => ( - Cow::from(ICON_EMAIL), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::ClosedEnvelope => unimplemented!(), - NoteTagShape::OpenEnvelope => unimplemented!(), - NoteTagShape::MobilePhone => unimplemented!(), - NoteTagShape::TelephoneWithClock => unimplemented!(), - NoteTagShape::QuestionBalloon => unimplemented!(), - NoteTagShape::PaperClip => unimplemented!(), - NoteTagShape::FrowningFace => unimplemented!(), - NoteTagShape::InstantMessagingContactPerson => unimplemented!(), - NoteTagShape::PersonWithExclamationMark => unimplemented!(), - NoteTagShape::TwoPeople => unimplemented!(), - NoteTagShape::ReminderBell => unimplemented!(), - NoteTagShape::Contact => ( - Cow::from(ICON_CONTACT), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::RoseOnAStem => unimplemented!(), - NoteTagShape::CalendarDateWithClock => unimplemented!(), - NoteTagShape::MusicalNote => ( - Cow::from(ICON_MUSIC), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::MovieClip => ( - Cow::from(ICON_FILM), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::QuotationMark => unimplemented!(), - NoteTagShape::Globe => unimplemented!(), - NoteTagShape::HyperlinkGlobe => ( - Cow::from(ICON_LINK), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::Laptop => unimplemented!(), - NoteTagShape::Plane => unimplemented!(), - NoteTagShape::Car => unimplemented!(), - NoteTagShape::Binoculars => unimplemented!(), - NoteTagShape::PresentationSlide => unimplemented!(), - NoteTagShape::Padlock => ( - Cow::from(ICON_LOCK), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::OpenBook => ( - Cow::from(ICON_BOOK), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::NotebookWithClock => unimplemented!(), - NoteTagShape::BlankPaperWithLines => ( - Cow::from(ICON_PAPER), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::Research => unimplemented!(), - NoteTagShape::Pen => ( - Cow::from(ICON_PEN), - self.icon_style(IconSize::Normal, style), - ), - NoteTagShape::DollarSign => unimplemented!(), - NoteTagShape::CoinsWithAWindowBackdrop => unimplemented!(), - NoteTagShape::ScheduledTask => unimplemented!(), - NoteTagShape::LightningBolt => unimplemented!(), - NoteTagShape::Cloud => unimplemented!(), - NoteTagShape::Heart => unimplemented!(), - NoteTagShape::Sunflower => unimplemented!(), - } - } - - fn icon_checkbox( - &self, - status: ActionItemStatus, - mut style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - style.set("fill", color.to_string()); - - if status.completed() { - ( - Cow::from(ICON_CHECKBOX_COMPLETE), - self.icon_style(IconSize::Large, style), - ) - } else { - ( - Cow::from(ICON_CHECKBOX_EMPTY), - self.icon_style(IconSize::Large, style), - ) - } - } - - fn icon_checkbox_with_person( - &self, - status: ActionItemStatus, - style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - self.icon_checkbox_with(status, style, color, ICON_PERSON) - } - - fn icon_checkbox_with_right_arrow( - &self, - status: ActionItemStatus, - style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - self.icon_checkbox_with(status, style, color, ICON_ARROW_RIGHT) - } - - fn icon_checkbox_with_star( - &self, - status: ActionItemStatus, - style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - self.icon_checkbox_with(status, style, color, ICON_STAR) - } - - fn icon_checkbox_with_flag( - &self, - status: ActionItemStatus, - style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - self.icon_checkbox_with(status, style, color, ICON_FLAG) - } - - fn icon_checkbox_with_1( - &self, - status: ActionItemStatus, - style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - self.icon_checkbox_with(status, style, color, "1") - } - - fn icon_checkbox_with_2( - &self, - status: ActionItemStatus, - style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - self.icon_checkbox_with(status, style, color, "2") - } - - fn icon_checkbox_with_3( - &self, - status: ActionItemStatus, - style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - self.icon_checkbox_with(status, style, color, "3") - } - - fn icon_checkbox_with_exclamation( - &self, - status: ActionItemStatus, - style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - self.icon_checkbox_with(status, style, color, "!") - } - - fn icon_checkbox_with( - &self, - status: ActionItemStatus, - mut style: StyleSet, - color: &'static str, - secondary_icon: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - style.set("fill", color.to_string()); - - let mut content = String::new(); - content.push_str(if status.completed() { - ICON_CHECKBOX_COMPLETE - } else { - ICON_CHECKBOX_EMPTY - }); - - content.push_str(&format!( - "{}", - secondary_icon - )); - - (Cow::from(content), self.icon_style(IconSize::Large, style)) - } - - fn icon_checkmark( - &self, - mut style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - style.set("fill", color.to_string()); - - ( - Cow::from(ICON_CHECK_MARK), - self.icon_style(IconSize::Large, style), - ) - } - - fn icon_circle( - &self, - mut style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - style.set("fill", color.to_string()); - - ( - Cow::from(ICON_CIRCLE), - self.icon_style(IconSize::Normal, style), - ) - } - - fn icon_square( - &self, - mut style: StyleSet, - color: &'static str, - ) -> (Cow<'static, str>, StyleSet) { - style.set("fill", color.to_string()); - - ( - Cow::from(ICON_SQUARE), - self.icon_style(IconSize::Large, style), - ) - } - - fn icon_style(&self, size: IconSize, mut style: StyleSet) -> StyleSet { - match size { - IconSize::Normal => { - style.set("height", "16px".to_string()); - style.set("width", "16px".to_string()); - } - IconSize::Large => { - style.set("height", "20px".to_string()); - style.set("width", "20px".to_string()); - } - } - - match (self.in_list, size) { - (false, IconSize::Normal) => { - style.set("left", "-23px".to_string()); - } - (false, IconSize::Large) => { - style.set("left", "-25px".to_string()); - } - (true, IconSize::Normal) => { - style.set("left", "-38px".to_string()); - } - (true, IconSize::Large) => { - style.set("left", "-40px".to_string()); - } - }; - - style - } -} diff --git a/packages/onenote-converter/src/page/outline.rs b/packages/onenote-converter/src/page/outline.rs deleted file mode 100644 index 65a15cab627..00000000000 --- a/packages/onenote-converter/src/page/outline.rs +++ /dev/null @@ -1,146 +0,0 @@ -use crate::page::Renderer; -use crate::parser::contents::{Outline, OutlineElement, OutlineItem}; -use crate::utils::{px, AttributeSet, StyleSet}; -use color_eyre::Result; - -impl<'a> Renderer<'a> { - pub(crate) fn render_outline(&mut self, outline: &Outline) -> Result { - let mut attrs = AttributeSet::new(); - let mut styles = StyleSet::new(); - let mut contents = String::new(); - - attrs.set("class", "container-outline".to_string()); - - if let Some(width) = outline.layout_max_width() { - let outline_width = if outline.is_layout_size_set_by_user() { - width - } else { - width.max(13.0) - }; - - styles.set("width", px(outline_width)); - }; - - if outline.offset_horizontal().is_some() || outline.offset_vertical().is_some() { - styles.set("position", "absolute".to_string()); - } - - if let Some(offset) = outline.offset_horizontal() { - styles.set("left", px(offset)); - } - - if let Some(offset) = outline.offset_vertical() { - styles.set("top", px(offset)); - } - - if styles.len() > 0 { - attrs.set("style", styles.to_string()); - } - - contents.push_str(&format!("
    ", attrs)); - contents.push_str(&self.render_outline_items( - outline.items(), - 0, - outline.child_level(), - outline.indents(), - )?); - contents.push_str("
    "); - - Ok(contents) - } - - pub(crate) fn render_outline_items( - &mut self, - items: &[OutlineItem], - parent_level: u8, - current_level: u8, - indents: &[f32], - ) -> Result { - self.render_list( - flatten_outline_items(items, parent_level, current_level), - indents, - ) - } - - pub(crate) fn render_outline_element( - &mut self, - element: &OutlineElement, - parent_level: u8, - current_level: u8, - indents: &[f32], - ) -> Result { - let mut indent_width = 0.0; - for i in (parent_level + 1)..=current_level { - indent_width += indents.get(i as usize).copied().unwrap_or(0.75); - } - - let mut contents = String::new(); - let is_list = self.is_list(element); - - let mut attrs = AttributeSet::new(); - attrs.set("class", "outline-element".to_string()); - - let mut styles = StyleSet::new(); - styles.set("margin-left", px(indent_width as f32)); - attrs.set("style", styles.to_string()); - - if is_list { - contents.push_str(&format!("
  • ", attrs)); - } else { - contents.push_str(&format!("
    ", attrs)); - } - - self.in_list = is_list; - - contents.extend( - element - .contents() - .iter() - .map(|content| self.render_content(content)) - .collect::, _>>()? - .into_iter(), - ); - - self.in_list = false; - - if !is_list { - contents.push_str("
    "); - } - - let children = element.children(); - - if !children.is_empty() { - contents.push_str(&self.render_outline_items( - children, - current_level, - current_level + element.child_level(), - indents, - )?); - } - - if is_list { - contents.push_str("
  • "); - } - - contents.push('\n'); - - Ok(contents) - } -} - -fn flatten_outline_items<'a>( - items: &'a [OutlineItem], - parent_level: u8, - current_level: u8, -) -> Box + 'a> { - Box::new(items.iter().flat_map(move |item| match item { - OutlineItem::Element(element) => { - Box::new(Some((element, parent_level, current_level)).into_iter()) - } - OutlineItem::Group(group) => flatten_outline_items( - group.outlines(), - parent_level, - current_level + group.child_level(), - ), - })) -} diff --git a/packages/onenote-converter/src/page/rich_text.rs b/packages/onenote-converter/src/page/rich_text.rs deleted file mode 100644 index c095b0f2552..00000000000 --- a/packages/onenote-converter/src/page/rich_text.rs +++ /dev/null @@ -1,306 +0,0 @@ -use crate::page::Renderer; -use crate::parser::contents::{EmbeddedObject, RichText}; -use crate::parser::property::common::ColorRef; -use crate::parser::property::rich_text::{ParagraphAlignment, ParagraphStyling}; -use crate::utils::{px, AttributeSet, StyleSet}; -use color_eyre::eyre::ContextCompat; -use color_eyre::Result; -use itertools::Itertools; -use once_cell::sync::Lazy; -use regex::{Captures, Regex}; - -impl<'a> Renderer<'a> { - pub(crate) fn render_rich_text(&mut self, text: &RichText) -> Result { - let mut content = String::new(); - let mut attrs = AttributeSet::new(); - let mut style = self.parse_paragraph_styles(text); - - if let Some((note_tag_html, note_tag_styles)) = self.render_note_tags(text.note_tags()) { - content.push_str(¬e_tag_html); - style.extend(note_tag_styles); - } - - content.push_str(&self.parse_content(text)?); - - if content.starts_with("http://") || content.starts_with("https://") { - content = format!("{}", content, content); - } - - if style.len() > 0 { - attrs.set("style", style.to_string()); - } - - match text.paragraph_style().style_id() { - Some(t) if !self.in_list && is_tag(t) => { - Ok(format!("<{} {}>{}", t, attrs, content, t)) - } - _ if style.len() > 0 => Ok(format!("{}", style, content)), - _ => Ok(content), - } - } - - fn parse_content(&mut self, data: &RichText) -> Result { - if !data.embedded_objects().is_empty() { - return Ok(data - .embedded_objects() - .iter() - .map(|object| match object { - EmbeddedObject::Ink(container) => { - self.render_ink(container.ink(), container.bounding_box(), true) - } - EmbeddedObject::InkSpace(space) => { - format!("", - px(space.width()), px(space.height())) - } - EmbeddedObject::InkLineBreak => { - "
    ".to_string() - } - }) - .collect_vec() - .join("")); - } - - let mut indices = data.text_run_indices().to_vec(); - let mut styles = data.text_run_formatting().to_vec(); - - let mut text = data.text().to_string(); - - if text.is_empty() { - text = " ".to_string(); - } - - // TODO: Maybe this shouldn't be here - // When the this character is at the start of the paragraph it makes - // all the styles to be shifted by minus one. - // A better solution would be to look if there isn't anything wrong with the parser, - // but I haven't found what could be causing this yet. - if text.starts_with("\u{000B}") && !indices.is_empty(){ - indices.remove(0); - styles.pop(); - } - - if indices.is_empty() { - return Ok(fix_newlines(&text)); - } - - assert!(indices.len() + 1 >= styles.len()); - - // Split text into parts specified by indices - let mut parts: Vec = vec![]; - - for i in indices.iter().copied().rev() { - let part = text.chars().skip(i as usize).collect(); - text = text.chars().take(i as usize).collect(); - - parts.push(part); - } - - if !indices.is_empty() { - parts.push(text); - } - - let mut in_hyperlink = false; - - let content = parts - .into_iter() - .rev() - .zip(styles.iter()) - .map(|(text, style)| { - if style.hyperlink() { - let text = self.render_hyperlink(text, style, in_hyperlink); - in_hyperlink = true; - - text - } else { - in_hyperlink = false; - - let style = self.parse_style(style); - - if style.len() > 0 { - Ok(format!("{}", style, text)) - } else { - Ok(text) - } - } - }) - .collect::>()?; - - Ok(fix_newlines(&content)) - } - - fn render_hyperlink( - &self, - text: String, - style: &ParagraphStyling, - in_hyperlink: bool, - ) -> Result { - const HYPERLINK_MARKER: &str = "\u{fddf}HYPERLINK \""; - - let style = self.parse_style(style); - - if text.starts_with(HYPERLINK_MARKER) { - let url = text - .strip_prefix(HYPERLINK_MARKER) - .wrap_err("Hyperlink has no start marker")? - .strip_suffix('"') - .wrap_err("Hyperlink has no end marker")?; - - Ok(format!("", url, style)) - } else if in_hyperlink { - Ok(text + "") - } else { - Ok(format!( - "{}", - text, style, text - )) - } - } - - fn parse_paragraph_styles(&self, text: &RichText) -> StyleSet { - if !text.embedded_objects().is_empty() { - assert_eq!( - text.text(), - "", - "paragraph with text and embedded objects is not supported" - ); - - return StyleSet::new(); - } - - let mut styles = self.parse_style(text.paragraph_style()); - - if let [style] = text.text_run_formatting() { - styles.extend(self.parse_style(style)) - } - - if text.paragraph_space_before() > 0.0 { - styles.set("padding-top", px(text.paragraph_space_before())) - } - - if text.paragraph_space_after() > 0.0 { - styles.set("padding-bottom", px(text.paragraph_space_after())) - } - - if let Some(line_spacing) = text.paragraph_line_spacing_exact() { - styles.set( - "line-height", - ((line_spacing as f32) * 50.0).floor().to_string() + "pt", - ); - // TODO: why not implemented? - // if line_spacing > 0.0 { - // dbg!(text); - // unimplemented!(); - // } - } - - match text.paragraph_alignment() { - ParagraphAlignment::Center => styles.set("text-align", "center".to_string()), - ParagraphAlignment::Right => styles.set("text-align", "right".to_string()), - _ => {} - } - - styles - } - - fn parse_style(&self, style: &ParagraphStyling) -> StyleSet { - let mut styles = StyleSet::new(); - - if style.bold() { - styles.set("font-weight", "bold".to_string()); - } - - if style.italic() { - styles.set("font-style", "italic".to_string()); - } - - if style.underline() { - styles.set("text-decoration", "underline".to_string()); - } - - if style.superscript() { - styles.set("vertical-align", "super".to_string()); - } - - if style.subscript() { - styles.set("vertical-align", "sub".to_string()); - } - - if style.strikethrough() { - styles.set("text-decoration", "line-through".to_string()); - } - - if let Some(font) = style.font() { - styles.set("font-family", font.to_string()); - } - - if let Some(size) = style.font_size() { - styles.set("font-size", ((size as f32) / 2.0).to_string() + "pt"); - } - - if let Some(ColorRef::Manual { r, g, b }) = style.font_color() { - styles.set("color", format!("rgb({},{},{})", r, g, b)); - } - - if let Some(ColorRef::Manual { r, g, b }) = style.highlight() { - styles.set("background-color", format!("rgb({},{},{})", r, g, b)); - } - - if style.paragraph_alignment().is_some() { - unimplemented!() - } - - if let Some(space) = style.paragraph_space_before() { - if space != 0.0 { - unimplemented!() - } - } - - if let Some(space) = style.paragraph_space_after() { - if space != 0.0 { - unimplemented!() - } - } - - if let Some(space) = style.paragraph_line_spacing_exact() { - if space != 0.0 { - unimplemented!() - } - - if let Some(size) = style.font_size() { - styles.set( - "line-height", - format!("{}px", (size as f32 * 1.2 / 72.0 * 48.0).floor()), - ) - } - } - - if style.math_formatting() { - // FIXME: Handle math formatting - // See https://docs.microsoft.com/en-us/windows/win32/api/richedit/ns-richedit-gettextex - // for unicode chars used - // unimplemented!() - } - - styles - } -} - -fn is_tag(tag: &str) -> bool { - !matches!(tag, "PageDateTime" | "PageTitle") -} - -fn fix_newlines(text: &str) -> String { - static REGEX_LEADING_SPACES: Lazy = - Lazy::new(|| Regex::new(r"
    (\s+)").expect("failed to compile regex")); - - let text = text - .replace("\u{000b}", "
    ") - .replace("\n", "
    ") - .replace("\r", "
    "); - - REGEX_LEADING_SPACES - .replace_all(&text, |captures: &Captures| { - "
    ".to_string() + &" ".repeat(captures[1].len()) - }) - .to_string() -} diff --git a/packages/onenote-converter/src/page/table.rs b/packages/onenote-converter/src/page/table.rs deleted file mode 100644 index 0d039a875ef..00000000000 --- a/packages/onenote-converter/src/page/table.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::page::Renderer; -use crate::parser::contents::{OutlineElement, Table, TableCell}; -use crate::utils::{px, AttributeSet, StyleSet}; -use color_eyre::Result; - -impl<'a> Renderer<'a> { - pub(crate) fn render_table(&mut self, table: &Table) -> Result { - let mut content = String::new(); - let mut styles = StyleSet::new(); - styles.set("border-collapse", "collapse".to_string()); - - if table.borders_visible() { - styles.set("border", "1pt solid #A3A3A3".to_string()); - } - - let mut attributes = AttributeSet::new(); - attributes.set("style", styles.to_string()); - attributes.set("cellspacing", "0".to_string()); - attributes.set("cellpadding", "0".to_string()); - - if table.borders_visible() { - attributes.set("border", "1".to_string()); - } - - content.push_str(&format!("", attributes.to_string())); - - let locked_cols = calc_locked_cols(table.cols_locked(), table.cols()); - - let mut col_widths = table.col_widths().to_vec(); - col_widths.extend(vec![0.0; table.cols() as usize - col_widths.len()].into_iter()); - let col_widths = &*col_widths; - - for row in table.contents() { - content.push_str(""); - - assert_eq!(row.contents().len(), col_widths.len()); - - let cells = row - .contents() - .iter() - .zip(col_widths.iter().copied()) - .zip(locked_cols.iter().copied()) - .map(|((cell, width), locked)| { - if locked { - (cell, Some(width)) - } else { - (cell, None) - } - }); - - for (cell, width) in cells { - self.render_table_cell(&mut content, cell, width)?; - } - - content.push_str(""); - } - - content.push_str("
    "); - - Ok(self.render_with_note_tags(table.note_tags(), content)) - } - - fn render_table_cell( - &mut self, - contents: &mut String, - cell: &TableCell, - width: Option, - ) -> Result<()> { - let mut styles = StyleSet::new(); - styles.set("padding", "2pt".to_string()); - styles.set("vertical-align", "top".to_string()); - styles.set("min-width", px(1.0)); - - if let Some(width) = width { - styles.set("width", px(width)); - } - - if let Some(color) = cell.background_color() { - styles.set( - "background", - format!("rgb({}, {}, {})", color.r(), color.g(), color.b()), - ) - } - - let mut attrs = AttributeSet::new(); - attrs.set("style", styles.to_string()); - - contents.push_str(&format!("", attrs.to_string())); - - let cell_level = self.table_cell_level(cell.contents()); - - let elements = cell.contents().iter().map(|el| (el, 0, cell_level)); - contents.push_str(&self.render_list(elements, cell.outline_indent_distance().value())?); - - contents.push_str(""); - - Ok(()) - } - - fn table_cell_level(&self, elements: &[OutlineElement]) -> u8 { - let needs_nesting = elements - .iter() - .any(|element| self.is_list(element) || self.has_note_tag(element)); - - if needs_nesting { - 2 - } else { - 1 - } - } -} - -fn calc_locked_cols(data: &[u8], count: u32) -> Vec { - if data.is_empty() { - return vec![false; count as usize]; - } - - (0..count) - .map(|i| data[i as usize / 8] & (1 << (i % 8)) == 1) - .collect() -} diff --git a/packages/onenote-converter/src/parser/errors.rs b/packages/onenote-converter/src/parser/errors.rs deleted file mode 100644 index ba20a4dba61..00000000000 --- a/packages/onenote-converter/src/parser/errors.rs +++ /dev/null @@ -1,123 +0,0 @@ -//! OneNote parsing error handling. - -use std::borrow::Cow; -use std::{io, string}; -use thiserror::Error; - -/// The result of parsing a OneNote file. -pub type Result = std::result::Result; - -/// A parsing error. -/// -/// If the crate is compiled with the `backtrace` feature enabled, the -/// parsing error struct will contain a backtrace of the location where -/// the error occured. The backtrace can be accessed using -/// [`std::error::Error::backtrace()`]. -#[derive(Error, Debug)] -#[error("{kind}")] -pub struct Error { - kind: ErrorKind, -} - -impl From for Error { - fn from(kind: ErrorKind) -> Self { - Error { kind } - } -} - -impl From for Error { - fn from(err: std::io::Error) -> Self { - ErrorKind::from(err).into() - } -} - -impl From for Error { - fn from(err: std::string::FromUtf16Error) -> Self { - ErrorKind::from(err).into() - } -} - -impl From for Error { - fn from(err: widestring::error::MissingNulTerminator) -> Self { - ErrorKind::from(err).into() - } -} - -impl From for Error { - fn from(err: uuid::Error) -> Self { - ErrorKind::from(err).into() - } -} - -/// Details about a parsing error -#[allow(missing_docs)] -#[derive(Error, Debug)] -pub enum ErrorKind { - /// Hit the end of the OneNote file before it was expected. - #[error("Unexpected end of file")] - UnexpectedEof, - - /// The parser was asked to process a table-of-contents file that turned out not to be one. - #[error("Not a table of contents file: {file}")] - NotATocFile { file: String }, - - /// The parser was asked to process a section file that turned out not to be one. - #[error("Not a section file: {file}")] - NotASectionFile { file: String }, - - /// When parsing a section group the table-of-contents file for this group was found to be missing. - #[error("Table of contents file is missing in dir {dir}")] - TocFileMissing { dir: String }, - - /// Malformed data was encountered when parsing the OneNote file. - #[error("Malformed data: {0}")] - MalformedData(Cow<'static, str>), - - /// Malformed data was encountered when parsing the OneNote data. - #[error("Malformed OneNote data: {0}")] - MalformedOneNoteData(Cow<'static, str>), - - /// Malformed data was encountered when parsing the OneNote file contents. - #[error("Malformed OneNote file data: {0}")] - MalformedOneNoteFileData(Cow<'static, str>), - - /// Malformed data was encountered when parsing the OneNote file contents. - #[error("Malformed OneNote incorrect type: {0}")] - MalformedOneNoteIncorrectType(String), - - /// Malformed data was encountered when parsing the OneStore data. - #[error("Malformed OneStore data: {0}")] - MalformedOneStoreData(Cow<'static, str>), - - /// Malformed data was encountered when parsing the FSSHTTPB data. - #[error("Malformed FSSHTTPB data: {0}")] - MalformedFssHttpBData(Cow<'static, str>), - - /// A malformed UUID was encountered - #[error("Invalid UUID: {err}")] - InvalidUuid { - #[from] - err: uuid::Error, - }, - - /// An I/O failure was encountered during parsing. - #[error("I/O failure: {err}")] - IO { - #[from] - err: io::Error, - }, - - /// A malformed UTF-16 string was encountered during parsing. - #[error("Malformed UTF-16 string: {err}")] - Utf16Error { - #[from] - err: string::FromUtf16Error, - }, - - /// A UTF-16 string without a null terminator was encountered during parsing. - #[error("UTF-16 string is missing null terminator: {err}")] - Utf16MissingNull { - #[from] - err: widestring::error::MissingNulTerminator, - }, -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data/binary_item.rs b/packages/onenote-converter/src/parser/fsshttpb/data/binary_item.rs deleted file mode 100644 index cb080e59f55..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data/binary_item.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::parser::errors::Result; -use crate::parser::fsshttpb::data::compact_u64::CompactU64; -use crate::parser::Reader; - -/// A byte array with the length determined by a `CompactU64`. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.3]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.3]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/6bdda105-af7f-4757-8dbe-0c7f3100647e -pub(crate) struct BinaryItem(Vec); - -impl BinaryItem { - pub(crate) fn parse(reader: Reader) -> Result { - let size = CompactU64::parse(reader)?.value(); - let data = reader.read(size as usize)?.to_vec(); - - Ok(BinaryItem(data)) - } - - pub(crate) fn value(self) -> Vec { - self.0 - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data/cell_id.rs b/packages/onenote-converter/src/parser/fsshttpb/data/cell_id.rs deleted file mode 100644 index cbac1702fe0..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data/cell_id.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::parser::errors::Result; -use crate::parser::fsshttpb::data::compact_u64::CompactU64; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::Reader; - -/// A FSSHTTP cell identifier. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.10] and [\[MS-FSSHTTPB\] 2.2.1.11]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.10]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/75bf8297-ef9c-458a-95a3-ad6265bfa864 -/// [\[MS-FSSHTTPB\] 2.2.1.11]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/d3f4d22d-6fb4-4032-8587-f3eb9c256e45 -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CellId(pub ExGuid, pub ExGuid); - -impl CellId { - pub(crate) fn parse(reader: Reader) -> Result { - let first = ExGuid::parse(reader)?; - let second = ExGuid::parse(reader)?; - - Ok(CellId(first, second)) - } - - pub(crate) fn parse_array(reader: Reader) -> Result> { - let mut values = vec![]; - - let count = CompactU64::parse(reader)?.value(); - for _ in 0..count { - values.push(CellId::parse(reader)?); - } - - Ok(values) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data/compact_u64.rs b/packages/onenote-converter/src/parser/fsshttpb/data/compact_u64.rs deleted file mode 100644 index cea2eb5ae66..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data/compact_u64.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::Reader; - -/// A compact unsigned 64-bit integer. -/// -/// The first byte encodes the total width of the integer. If the first byte is zero, there is no -/// further data and the integer value is zero. Otherwise the index of the lowest bit with value 1 -/// of the first byte indicates the width of the remaining integer data: -/// If the lowest bit is set, the integer data is 1 byte wide; if the second bit is set, the -/// integer data is 2 bytes wide etc. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.1]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.1]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/8eb74ebe-81d1-4569-a29a-308a6128a52f -#[derive(Debug)] -pub(crate) struct CompactU64(u64); - -impl CompactU64 { - pub(crate) fn value(&self) -> u64 { - self.0 - } - - pub(crate) fn parse(reader: Reader) -> Result { - let bytes = reader.bytes(); - - let first_byte = bytes.first().copied().ok_or(ErrorKind::UnexpectedEof)?; - - if first_byte == 0 { - reader.advance(1)?; - - return Ok(CompactU64(0)); - } - - if first_byte & 1 != 0 { - return Ok(CompactU64((reader.get_u8()? >> 1) as u64)); - } - - if first_byte & 2 != 0 { - return Ok(CompactU64((reader.get_u16()? >> 2) as u64)); - } - - if first_byte & 4 != 0 { - if reader.remaining() < 3 { - return Err(ErrorKind::UnexpectedEof.into()); - } - - let value = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], 0]); - - reader.advance(3)?; - - return Ok(CompactU64((value >> 3) as u64)); - } - - if first_byte & 8 != 0 { - if reader.remaining() < 4 { - return Err(ErrorKind::UnexpectedEof.into()); - } - - let value = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]); - - reader.advance(4)?; - - return Ok(CompactU64((value >> 4) as u64)); - } - - if first_byte & 16 != 0 { - if reader.remaining() < 5 { - return Err(ErrorKind::UnexpectedEof.into()); - } - - let value = - u64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], 0, 0, 0]); - - reader.advance(5)?; - - return Ok(CompactU64(value >> 5)); - } - - if first_byte & 32 != 0 { - if reader.remaining() < 6 { - return Err(ErrorKind::UnexpectedEof.into()); - } - - let value = u64::from_le_bytes([ - first_byte, bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], 0, 0, - ]); - - reader.advance(6)?; - - return Ok(CompactU64(value >> 6)); - } - - if first_byte & 64 != 0 { - if reader.remaining() < 7 { - return Err(ErrorKind::UnexpectedEof.into()); - } - - let value = u64::from_le_bytes([ - first_byte, bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], 0, - ]); - - reader.advance(7)?; - - return Ok(CompactU64(value >> 7)); - } - - if first_byte & 128 != 0 { - reader.advance(1)?; - - return Ok(CompactU64(reader.get_u64()?)); - } - - panic!("unexpected compact u64 type: {:x}", first_byte) - } -} - -#[cfg(test)] -mod test { - use crate::parser::fsshttpb::data::compact_u64::CompactU64; - use crate::parser::reader::Reader; - - #[test] - fn test_zero() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0u8])).unwrap().value(), - 0 - ); - } - - #[test] - fn test_7_bit() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0u8])).unwrap().value(), - 0 - ); - } - - #[test] - fn test_14_bit() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0u8])).unwrap().value(), - 0 - ); - } - - #[test] - fn test_21_bit() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0xd4u8, 0x8b, 0x10])) - .unwrap() - .value(), - 135546 - ); - } - - #[test] - fn test_28_bit() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0u8])).unwrap().value(), - 0 - ); - } - - #[test] - fn test_35_bit() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0u8])).unwrap().value(), - 0 - ); - } - - #[test] - fn test_42_bit() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0u8])).unwrap().value(), - 0 - ); - } - - #[test] - fn test_49_bit() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0u8])).unwrap().value(), - 0 - ); - } - - #[test] - fn test_64_bit() { - assert_eq!( - CompactU64::parse(&mut Reader::new(&[0u8])).unwrap().value(), - 0 - ); - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data/exguid.rs b/packages/onenote-converter/src/parser/fsshttpb/data/exguid.rs deleted file mode 100644 index fa25191e9d1..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data/exguid.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::compact_u64::CompactU64; -use crate::parser::shared::guid::Guid; -use crate::parser::Reader; -use std::fmt; - -/// A variable-width encoding of an extended GUID (GUID + 32 bit value) -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.7]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.7]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/bff58e9f-8222-4fbb-b112-5826d5febedd -#[derive(Clone, Copy, PartialEq, Hash, Eq)] -pub struct ExGuid { - pub guid: Guid, - pub value: u32, -} - -impl ExGuid { - pub fn fallback() -> ExGuid { - return ExGuid { - guid: Guid::nil(), - value: 0, - }; - } - - pub(crate) fn is_nil(&self) -> bool { - self.guid.is_nil() && self.value == 0 - } - - pub(crate) fn as_option(&self) -> Option { - if self.is_nil() { - None - } else { - Some(*self) - } - } - - pub(crate) fn from_guid(guid: Guid, value: u32) -> ExGuid { - ExGuid { guid, value } - } - - pub(crate) fn parse(reader: Reader) -> Result { - let data = reader.get_u8()?; - - // A null ExGuid ([FSSHTTPB] 2.2.1.7.1) - if data == 0 { - return Ok(ExGuid { - guid: Guid::nil(), - value: 0, - }); - } - - // A ExGuid with a 5 bit value ([FSSHTTPB] 2.2.1.7.2) - if data & 0b111 == 4 { - return Ok(ExGuid { - guid: Guid::parse(reader)?, - value: (data >> 3) as u32, - }); - } - - // A ExGuid with a 10 bit value ([FSSHTTPB] 2.2.1.7.3) - if data & 0b111111 == 32 { - let value = (reader.get_u8()? as u16) << 2 | (data >> 6) as u16; - - return Ok(ExGuid { - guid: Guid::parse(reader)?, - value: value as u32, - }); - } - - // A ExGuid with a 17 bit value ([FSSHTTPB] 2.2.1.7.4) - if data & 0b1111111 == 64 { - let value = (reader.get_u16()? as u32) << 1 | (data >> 7) as u32; - - return Ok(ExGuid { - guid: Guid::parse(reader)?, - value, - }); - } - - // A ExGuid with a 32 bit value ([FSSHTTPB] 2.2.1.7.5) - if data == 128 { - let value = reader.get_u32()?; - - return Ok(ExGuid { - guid: Guid::parse(reader)?, - value, - }); - } - - Err( - ErrorKind::MalformedData(format!("unexpected ExGuid first byte: {:b}", data).into()) - .into(), - ) - } - - /// Parse an array of `ExGuid` values. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.8] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.8]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/10d6fb35-d630-4ae3-b530-b9e877fc27d3 - pub(crate) fn parse_array(reader: Reader) -> Result> { - let mut values = vec![]; - - let count = CompactU64::parse(reader)?.value(); - for _ in 0..count { - values.push(ExGuid::parse(reader)?); - } - - Ok(values) - } -} - -impl fmt::Debug for ExGuid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ExGuid {{{}, {}}}", self.guid, self.value) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data/mod.rs b/packages/onenote-converter/src/parser/fsshttpb/data/mod.rs deleted file mode 100644 index 715c96cc3c5..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub(crate) mod binary_item; -pub(crate) mod cell_id; -pub(crate) mod compact_u64; -pub(crate) mod exguid; -pub(crate) mod object_types; -pub(crate) mod serial_number; -pub(crate) mod stream_object; diff --git a/packages/onenote-converter/src/parser/fsshttpb/data/object_types.rs b/packages/onenote-converter/src/parser/fsshttpb/data/object_types.rs deleted file mode 100644 index c9d10bfa237..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data/object_types.rs +++ /dev/null @@ -1,51 +0,0 @@ -use enum_primitive_derive::Primitive; -use num_traits::ToPrimitive; -use std::fmt; - -/// Stream object types. -/// -/// While the FSSHTTPB protocol specified more object types than listed here, we only need a limited -/// number of them to parse OneNote files stored in FSSHTTPB format. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.5.1] and [\[MS-FSSHTTPB\] 2.2.1.5.2]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.5.1]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/a1017f48-a888-49ff-b71d-cc3c707f753a -/// [\[MS-FSSHTTPB\] 2.2.1.5.2]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/ac629d63-60a1-49b2-9db2-fa3c19971cc9 -#[derive(Debug, Primitive, PartialEq)] -pub enum ObjectType { - CellManifest = 0x0B, - DataElement = 0x01, - DataElementFragment = 0x06A, - DataElementPackage = 0x15, - ObjectDataBlob = 0x02, - ObjectGroupBlobReference = 0x1C, - ObjectGroupData = 0x1E, - ObjectGroupDataBlob = 0x05, - ObjectGroupDataExcluded = 0x03, - ObjectGroupDataObject = 0x16, - ObjectGroupDeclaration = 0x1D, - ObjectGroupMetadata = 0x078, - ObjectGroupMetadataBlock = 0x79, - ObjectGroupObject = 0x18, - /// An indicator that the object contains a OneNote packing object. - /// - /// See [\[MS-ONESTORE\] 2.8.1] (look for _Packaging Start_) - /// - /// [\[MS-ONESTORE\] 2.8.1]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-onestore/a2f046ea-109a-49c4-912d-dc2888cf0565 - OneNotePackaging = 0x7a, - RevisionManifest = 0x1A, - RevisionManifestGroupReference = 0x19, - RevisionManifestRoot = 0x0A, - StorageIndexCellMapping = 0x0E, - StorageIndexManifestMapping = 0x11, - StorageIndexRevisionMapping = 0x0D, - StorageManifest = 0x0C, - StorageManifestRoot = 0x07, -} - -impl fmt::LowerHex for ObjectType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let value = self.to_u64().unwrap(); - fmt::LowerHex::fmt(&value, f) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data/serial_number.rs b/packages/onenote-converter/src/parser/fsshttpb/data/serial_number.rs deleted file mode 100644 index 318b015e367..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data/serial_number.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::parser::errors::Result; -use crate::parser::shared::guid::Guid; -use crate::parser::Reader; - -/// A variable-width serial number. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.9]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.9]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/9db15fa4-0dc2-4b17-b091-d33886d8a0f6 -#[derive(Debug)] -#[allow(dead_code)] -pub struct SerialNumber { - pub guid: Guid, - pub serial: u64, -} - -impl SerialNumber { - pub(crate) fn parse(reader: Reader) -> Result { - let serial_type = reader.get_u8()?; - - // A null-value ([FSSHTTPB] 2.2.1.9.1) - if serial_type == 0 { - return Ok(SerialNumber { - guid: Guid::nil(), - serial: 0, - }); - } - - // A serial number with a 64 bit value ([FSSHTTPB] 2.2.1.9.2) - let guid = Guid::parse(reader)?; - let serial = reader.get_u64()?; - - Ok(SerialNumber { guid, serial }) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data/stream_object.rs b/packages/onenote-converter/src/parser/fsshttpb/data/stream_object.rs deleted file mode 100644 index d65c766a94a..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data/stream_object.rs +++ /dev/null @@ -1,234 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::compact_u64::CompactU64; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::Reader; -use num_traits::{FromPrimitive, ToPrimitive}; - -/// A FSSHTTPB stream object header. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.5]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.5]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/5faee10f-8e55-43f8-935a-d6e4294856fc -#[derive(Debug)] -#[allow(dead_code)] -pub struct ObjectHeader { - pub compound: bool, - pub object_type: ObjectType, - pub length: u64, -} - -impl ObjectHeader { - pub(crate) fn try_parse(reader: Reader, object_type: ObjectType) -> Result<()> { - Self::try_parse_start(reader, object_type, Self::parse) - } - - /// Parse a 16-bit or 32-bit stream object header. - pub(crate) fn parse(reader: Reader) -> Result { - let header_type = reader.bytes().first().ok_or(ErrorKind::UnexpectedEof)?; - - match header_type & 0b11 { - 0x0 => Self::parse_16(reader), - 0x2 => Self::parse_32(reader), - _ => Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object header type: {:x}", header_type).into(), - ) - .into()), - } - } - - pub(crate) fn try_parse_16(reader: Reader, object_type: ObjectType) -> Result<()> { - Self::try_parse_start(reader, object_type, Self::parse_16) - } - - /// Parse a 16 bit stream object header. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.5.1] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.5.1]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/a1017f48-a888-49ff-b71d-cc3c707f753a - pub(crate) fn parse_16(reader: Reader) -> Result { - let data = reader.get_u16()?; - - let header_type = data & 0b11; - if header_type != 0x0 { - return Err(ErrorKind::MalformedFssHttpBData( - format!( - "unexpected object header type for 16 bit header: 0x{:x}", - header_type - ) - .into(), - ) - .into()); - } - - let compound = data & 0x4 == 0x4; - let object_type_value = (data >> 3) & 0x3f; - let object_type = if let Some(object_type) = ObjectType::from_u16(object_type_value) { - object_type - } else { - return Err(ErrorKind::MalformedFssHttpBData( - format!("invalid object type: 0x{:x}", object_type_value).into(), - ) - .into()); - }; - let length = (data >> 9) as u64; - - Ok(ObjectHeader { - compound, - object_type, - length, - }) - } - - pub(crate) fn try_parse_32(reader: Reader, object_type: ObjectType) -> Result<()> { - Self::try_parse_start(reader, object_type, Self::parse_32) - } - - /// Parse a 32 bit stream object header. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.5.2] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.5.2]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/ac629d63-60a1-49b2-9db2-fa3c19971cc9 - fn parse_32(reader: Reader) -> Result { - let data = reader.get_u32()?; - - let header_type = data & 0b11; - if header_type != 0x2 { - return Err(ErrorKind::MalformedFssHttpBData( - format!( - "unexpected object header type for 32 bit header: 0x{:x}", - header_type - ) - .into(), - ) - .into()); - } - - let compound = data & 0x4 == 0x4; - let object_type_value = (data >> 3) & 0x3fff; - let object_type = if let Some(object_type) = ObjectType::from_u32(object_type_value) { - object_type - } else { - return Err(ErrorKind::MalformedFssHttpBData( - format!("invalid object type: 0x{:x}", object_type_value).into(), - ) - .into()); - }; - let mut length = (data >> 17) as u64; - - if length == 0x7fff { - length = CompactU64::parse(reader)?.value(); - } - - Ok(ObjectHeader { - compound, - object_type, - length, - }) - } - - pub(crate) fn try_parse_end_16(reader: Reader, object_type: ObjectType) -> Result<()> { - Self::try_parse_end(reader, object_type, Self::parse_end_16) - } - - /// Parse a 16-bit stream object header end. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.5.4] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.5.4]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/d8cedbb8-073b-4711-8867-f88b887ab0a9 - fn parse_end_16(reader: Reader) -> Result { - let data = reader.get_u16()?; - let header_type = data & 0b11; - if header_type != 0x3 { - return Err(ErrorKind::MalformedFssHttpBData( - format!( - "unexpected object header type for 16 bit end header: {:x}", - header_type - ) - .into(), - ) - .into()); - } - - let object_type_value = data >> 2; - - if let Some(object_type) = ObjectType::from_u16(object_type_value) { - Ok(object_type) - } else { - Err(ErrorKind::MalformedFssHttpBData( - format!("invalid object type: 0x{:x}", object_type_value).into(), - ) - .into()) - } - } - - pub(crate) fn try_parse_end_8(reader: Reader, object_type: ObjectType) -> Result<()> { - Self::try_parse_end(reader, object_type, Self::parse_end_8) - } - - /// Parse a 8-bit stream object header end. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.5.3] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.5.3]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/544ce81a-44e3-48ff-b094-0e51c7207aa1 - fn parse_end_8(reader: Reader) -> Result { - let data = reader.get_u8()?; - let header_type = data & 0b11; - if header_type != 0x1 { - return Err(ErrorKind::MalformedFssHttpBData( - format!( - "unexpected object header type for 8 bit end header: {:x}", - header_type - ) - .into(), - ) - .into()); - } - - let object_type_value = data >> 2; - - if let Some(object_type) = ObjectType::from_u8(object_type_value) { - Ok(object_type) - } else { - Err(ErrorKind::MalformedFssHttpBData( - format!("invalid object type: 0x{:x}", object_type_value).into(), - ) - .into()) - } - } - - pub(crate) fn has_end_8(reader: Reader, object_type: ObjectType) -> Result { - let data = reader.bytes().first().ok_or(ErrorKind::UnexpectedEof)?; - - Ok(data & 0b11 == 0x1 && data >> 2 == object_type.to_u8().unwrap()) - } - - fn try_parse_start( - reader: Reader, - object_type: ObjectType, - parse: fn(Reader) -> Result, - ) -> Result<()> { - match parse(reader) { - Ok(header) if header.object_type == object_type => Ok(()), - Ok(header) => Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object type: {:x}", header.object_type).into(), - ) - .into()), - Err(e) => Err(e), - } - } - - fn try_parse_end( - reader: Reader, - object_type: ObjectType, - parse: fn(Reader) -> Result, - ) -> Result<()> { - match parse(reader) { - Ok(header) if header == object_type => Ok(()), - Ok(header) => Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object type: {:x}", header).into(), - ) - .into()), - Err(e) => Err(e), - } - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data_element/cell_manifest.rs b/packages/onenote-converter/src/parser/fsshttpb/data_element/cell_manifest.rs deleted file mode 100644 index 2ed32eb9147..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data_element/cell_manifest.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::parser::errors::Result; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::DataElement; -use crate::parser::Reader; - -impl DataElement { - /// Parse a cell manifest. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.12.4] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.12.4]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/541f7f92-ee5d-407e-9ece-fb1b35832a10 - pub(crate) fn parse_cell_manifest(reader: Reader) -> Result { - ObjectHeader::try_parse_16(reader, ObjectType::CellManifest)?; - - let id = ExGuid::parse(reader)?; - - ObjectHeader::try_parse_end_8(reader, ObjectType::DataElement)?; - - Ok(id) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data_element/data_element_fragment.rs b/packages/onenote-converter/src/parser/fsshttpb/data_element/data_element_fragment.rs deleted file mode 100644 index 9cc22f34e05..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data_element/data_element_fragment.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::parser::errors::Result; -use crate::parser::fsshttpb::data::compact_u64::CompactU64; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::DataElement; -use crate::parser::Reader; - -/// A data element fragment. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.7]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.7]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/9a860e3b-cf61-484b-8ee3-d875afaf7a05 -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct DataElementFragment { - pub(crate) id: ExGuid, - pub(crate) size: u64, - pub(crate) chunk_reference: DataElementFragmentChunkReference, - pub(crate) data: Vec, -} - -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct DataElementFragmentChunkReference { - pub(crate) offset: u64, - pub(crate) length: u64, -} - -impl DataElement { - /// Parse a data element fragment. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.12.7] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.12.7]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/9a860e3b-cf61-484b-8ee3-d875afaf7a05 - pub(crate) fn parse_data_element_fragment(reader: Reader) -> Result { - ObjectHeader::try_parse(reader, ObjectType::DataElementFragment)?; - - let id = ExGuid::parse(reader)?; - let size = CompactU64::parse(reader)?.value(); - let offset = CompactU64::parse(reader)?.value(); - let length = CompactU64::parse(reader)?.value(); - - let data = reader.read(size as usize)?.to_vec(); - - let chunk_reference = DataElementFragmentChunkReference { offset, length }; - let fragment = DataElementFragment { - id, - size, - chunk_reference, - data, - }; - - Ok(fragment) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data_element/mod.rs b/packages/onenote-converter/src/parser/fsshttpb/data_element/mod.rs deleted file mode 100644 index 2f1d62812d4..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data_element/mod.rs +++ /dev/null @@ -1,196 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::compact_u64::CompactU64; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::serial_number::SerialNumber; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::data_element_fragment::DataElementFragment; -use crate::parser::fsshttpb::data_element::object_data_blob::ObjectDataBlob; -use crate::parser::fsshttpb::data_element::object_group::ObjectGroup; -use crate::parser::fsshttpb::data_element::revision_manifest::RevisionManifest; -use crate::parser::fsshttpb::data_element::storage_index::StorageIndex; -use crate::parser::fsshttpb::data_element::storage_manifest::StorageManifest; -use crate::parser::Reader; -use std::collections::HashMap; -use std::fmt::Debug; - -pub(crate) mod cell_manifest; -pub(crate) mod data_element_fragment; -pub(crate) mod object_data_blob; -pub(crate) mod object_group; -pub(crate) mod revision_manifest; -pub(crate) mod storage_index; -pub(crate) mod storage_manifest; - -/// A FSSHTTPB data element package. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12]. -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/99a25464-99b5-4262-a964-baabed2170eb -#[derive(Debug)] -pub(crate) struct DataElementPackage { - pub(crate) storage_indexes: HashMap, - pub(crate) storage_manifests: HashMap, - pub(crate) cell_manifests: HashMap, - pub(crate) revision_manifests: HashMap, - pub(crate) object_groups: HashMap, - pub(crate) data_element_fragments: HashMap, - pub(crate) object_data_blobs: HashMap, -} - -impl DataElementPackage { - pub(crate) fn parse(reader: Reader) -> Result { - ObjectHeader::try_parse_16(reader, ObjectType::DataElementPackage)?; - - if reader.get_u8()? != 0 { - return Err(ErrorKind::MalformedFssHttpBData("invalid padding byte".into()).into()); - } - - let mut package = DataElementPackage { - storage_indexes: Default::default(), - storage_manifests: Default::default(), - cell_manifests: Default::default(), - revision_manifests: Default::default(), - object_groups: Default::default(), - data_element_fragments: Default::default(), - object_data_blobs: Default::default(), - }; - - loop { - if ObjectHeader::has_end_8(reader, ObjectType::DataElementPackage)? { - break; - } - - DataElement::parse(reader, &mut package)? - } - - ObjectHeader::try_parse_end_8(reader, ObjectType::DataElementPackage)?; - - Ok(package) - } - - /// Look up the object groups referenced by a cell. - pub(crate) fn find_objects( - &self, - cell: ExGuid, - storage_index: &StorageIndex, - ) -> Result> { - let revision_id = self - .find_cell_revision_id(cell) - .ok_or_else(|| ErrorKind::MalformedFssHttpBData("cell revision id not found".into()))?; - let revision_mapping_id = storage_index - .find_revision_mapping_id(revision_id) - .ok_or_else(|| { - ErrorKind::MalformedFssHttpBData("revision mapping id not found".into()) - })?; - let revision_manifest = self - .find_revision_manifest(revision_mapping_id) - .ok_or_else(|| { - ErrorKind::MalformedFssHttpBData("revision manifest not found".into()) - })?; - - revision_manifest - .group_references - .iter() - .map(|reference| { - self.find_object_group(*reference).ok_or_else(|| { - ErrorKind::MalformedFssHttpBData("object group not found".into()).into() - }) - }) - .collect::>() - } - - /// Look up a blob by its ID. - pub(crate) fn find_blob(&self, id: ExGuid) -> Option<&[u8]> { - self.object_data_blobs.get(&id).map(|blob| blob.value()) - } - - /// Find the first storage index. - pub(crate) fn find_storage_index(&self) -> Option<&StorageIndex> { - self.storage_indexes.values().next() - } - - /// Find the first storage manifest. - pub(crate) fn find_storage_manifest(&self) -> Option<&StorageManifest> { - self.storage_manifests.values().next() - } - - /// Look up a cell revision ID by the cell's manifest ID. - pub(crate) fn find_cell_revision_id(&self, id: ExGuid) -> Option { - self.cell_manifests.get(&id).copied() - } - - /// Look up a revision manifest by its ID. - pub(crate) fn find_revision_manifest(&self, id: ExGuid) -> Option<&RevisionManifest> { - self.revision_manifests.get(&id) - } - - /// Look up an object group by its ID. - pub(crate) fn find_object_group(&self, id: ExGuid) -> Option<&ObjectGroup> { - self.object_groups.get(&id) - } -} - -/// A parser for a single data element. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.1] -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.1]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/f0901ac0-4f26-413f-805b-a6830781f64c -#[derive(Debug)] -pub(crate) struct DataElement; - -impl DataElement { - pub(crate) fn parse(reader: Reader, package: &mut DataElementPackage) -> Result<()> { - ObjectHeader::try_parse_16(reader, ObjectType::DataElement)?; - - let id = ExGuid::parse(reader)?; - let _serial = SerialNumber::parse(reader)?; - let element_type = CompactU64::parse(reader)?; - - match element_type.value() { - 0x01 => { - package - .storage_indexes - .insert(id, Self::parse_storage_index(reader)?); - } - 0x02 => { - package - .storage_manifests - .insert(id, Self::parse_storage_manifest(reader)?); - } - 0x03 => { - package - .cell_manifests - .insert(id, Self::parse_cell_manifest(reader)?); - } - 0x04 => { - package - .revision_manifests - .insert(id, Self::parse_revision_manifest(reader)?); - } - 0x05 => { - package - .object_groups - .insert(id, Self::parse_object_group(reader)?); - } - 0x06 => { - package - .data_element_fragments - .insert(id, Self::parse_data_element_fragment(reader)?); - } - 0x0A => { - package - .object_data_blobs - .insert(id, Self::parse_object_data_blob(reader)?); - } - x => { - return Err(ErrorKind::MalformedFssHttpBData( - format!("invalid element type: 0x{:X}", x).into(), - ) - .into()) - } - } - - Ok(()) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data_element/object_data_blob.rs b/packages/onenote-converter/src/parser/fsshttpb/data_element/object_data_blob.rs deleted file mode 100644 index da3088d518c..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data_element/object_data_blob.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::parser::errors::Result; -use crate::parser::fsshttpb::data::binary_item::BinaryItem; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::DataElement; -use crate::parser::Reader; -use std::fmt; - -/// An object data blob. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.8] -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.8]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/d36dd2b4-bad1-441b-93c7-adbe3069152c -pub(crate) struct ObjectDataBlob(Vec); - -impl ObjectDataBlob { - pub(crate) fn value(&self) -> &[u8] { - &self.0 - } -} - -impl fmt::Debug for ObjectDataBlob { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ObjectDataBlob({} bytes)", self.0.len()) - } -} - -impl DataElement { - pub(crate) fn parse_object_data_blob(reader: Reader) -> Result { - ObjectHeader::try_parse(reader, ObjectType::ObjectDataBlob)?; - - let data = BinaryItem::parse(reader)?; - - ObjectHeader::try_parse_end_8(reader, ObjectType::DataElement)?; - - Ok(ObjectDataBlob(data.value())) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data_element/object_group.rs b/packages/onenote-converter/src/parser/fsshttpb/data_element/object_group.rs deleted file mode 100644 index e542d781f6f..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data_element/object_group.rs +++ /dev/null @@ -1,336 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::binary_item::BinaryItem; -use crate::parser::fsshttpb::data::cell_id::CellId; -use crate::parser::fsshttpb::data::compact_u64::CompactU64; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::DataElement; -use crate::parser::Reader; -use std::fmt; - -/// An object group. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.6] -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.6]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/21404be6-0334-490e-80b5-82fccb9c04af -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct ObjectGroup { - pub(crate) declarations: Vec, - pub(crate) metadata: Vec, - pub(crate) objects: Vec, -} - -/// An object group declaration. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.6.1] -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.6.1]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/ef660e4b-a099-4e76-81f7-ed5c04a70caa -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) enum ObjectGroupDeclaration { - Object { - object_id: ExGuid, - partition_id: u64, - data_size: u64, - object_reference_count: u64, - cell_reference_count: u64, - }, - Blob { - object_id: ExGuid, - blob_id: ExGuid, - partition_id: u64, - object_reference_count: u64, - cell_reference_count: u64, - }, -} - -impl ObjectGroupDeclaration { - pub(crate) fn partition_id(&self) -> u64 { - match self { - ObjectGroupDeclaration::Object { partition_id, .. } => *partition_id, - ObjectGroupDeclaration::Blob { partition_id, .. } => *partition_id, - } - } - - pub(crate) fn object_id(&self) -> ExGuid { - match self { - ObjectGroupDeclaration::Object { object_id, .. } => *object_id, - ObjectGroupDeclaration::Blob { object_id, .. } => *object_id, - } - } -} - -/// An object group's metadata. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.6.3] and [\[MS-FSSHTTPB\] 2.2.1.12.6.3.1] -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.6.3]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/d35a8e21-e139-455c-a20b-3f47a5d9fb89 -/// [\[MS-FSSHTTPB\] 2.2.1.12.6.3.1]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/507c6b42-2772-4319-b530-8fbbf4d34afd -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct ObjectGroupMetadata { - pub(crate) change_frequency: ObjectChangeFrequency, -} - -#[derive(Debug)] -pub(crate) enum ObjectChangeFrequency { - Unknown = 0, - Frequent = 1, - Infrequent = 2, - Independent = 3, - Custom = 4, -} - -impl ObjectChangeFrequency { - fn parse(value: u64) -> ObjectChangeFrequency { - match value { - x if x == ObjectChangeFrequency::Unknown as u64 => ObjectChangeFrequency::Unknown, - x if x == ObjectChangeFrequency::Frequent as u64 => ObjectChangeFrequency::Frequent, - x if x == ObjectChangeFrequency::Infrequent as u64 => ObjectChangeFrequency::Infrequent, - x if x == ObjectChangeFrequency::Independent as u64 => { - ObjectChangeFrequency::Independent - } - x if x == ObjectChangeFrequency::Custom as u64 => ObjectChangeFrequency::Custom, - x => panic!("unexpected change frequency: {}", x), - } - } -} - -/// An object group's data. -pub(crate) enum ObjectGroupData { - /// An object. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.12.6.4] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.12.6.4]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/d542b89c-9e81-4af6-885a-47b2f9c1ce53 - Object { - group: Vec, - cells: Vec, - data: Vec, - }, - /// An excluded object. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.12.6.4] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.12.6.4]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/d542b89c-9e81-4af6-885a-47b2f9c1ce53 - ObjectExcluded { - group: Vec, - cells: Vec, - size: u64, - }, - /// A blob reference. - /// - /// See [\[MS-FSSHTTPB\] 2.2.1.12.6.5] - /// - /// [\[MS-FSSHTTPB\] 2.2.1.12.6.5]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/9f73af5e-bd70-4703-8ec6-1866338f1b91 - BlobReference { - objects: Vec, - cells: Vec, - blob: ExGuid, - }, -} - -struct DebugSize(usize); - -impl fmt::Debug for ObjectGroupData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ObjectGroupData::Object { group, cells, data } => f - .debug_struct("Object") - .field("group", group) - .field("cells", cells) - .field("data", &DebugSize(data.len())) - .finish(), - ObjectGroupData::ObjectExcluded { group, cells, size } => f - .debug_struct("ObjectExcluded") - .field("group", group) - .field("cells", cells) - .field("size", size) - .finish(), - ObjectGroupData::BlobReference { - objects, - cells, - blob, - } => f - .debug_struct("ObjectExcluded") - .field("objects", objects) - .field("cells", cells) - .field("blob", blob) - .finish(), - } - } -} - -impl fmt::Debug for DebugSize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} bytes", self.0) - } -} - -impl DataElement { - pub(crate) fn parse_object_group(reader: Reader) -> Result { - let declarations = DataElement::parse_object_group_declarations(reader)?; - - let mut metadata = vec![]; - - let object_header = ObjectHeader::parse(reader)?; - match object_header.object_type { - ObjectType::ObjectGroupMetadataBlock => { - metadata = DataElement::parse_object_group_metadata(reader)?; - - // Parse object header for the group data section - let object_header = ObjectHeader::parse(reader)?; - if object_header.object_type != ObjectType::ObjectGroupData { - return Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object type: {:x}", object_header.object_type).into(), - ) - .into()); - } - } - ObjectType::ObjectGroupData => {} // Skip, will be parsed below - _ => { - return Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object type: {:x}", object_header.object_type).into(), - ) - .into()) - } - } - let objects = DataElement::parse_object_group_data(reader)?; - - ObjectHeader::try_parse_end_8(reader, ObjectType::DataElement)?; - - Ok(ObjectGroup { - declarations, - metadata, - objects, - }) - } - - fn parse_object_group_declarations(reader: Reader) -> Result> { - ObjectHeader::try_parse(reader, ObjectType::ObjectGroupDeclaration)?; - - let mut declarations = vec![]; - - loop { - if ObjectHeader::has_end_8(reader, ObjectType::ObjectGroupDeclaration)? { - break; - } - - let object_header = ObjectHeader::parse(reader)?; - match object_header.object_type { - ObjectType::ObjectGroupObject => { - let object_id = ExGuid::parse(reader)?; - let partition_id = CompactU64::parse(reader)?.value(); - let data_size = CompactU64::parse(reader)?.value(); - let object_reference_count = CompactU64::parse(reader)?.value(); - let cell_reference_count = CompactU64::parse(reader)?.value(); - - declarations.push(ObjectGroupDeclaration::Object { - object_id, - partition_id, - data_size, - object_reference_count, - cell_reference_count, - }) - } - ObjectType::ObjectGroupDataBlob => { - let object_id = ExGuid::parse(reader)?; - let blob_id = ExGuid::parse(reader)?; - let partition_id = CompactU64::parse(reader)?.value(); - let object_reference_count = CompactU64::parse(reader)?.value(); - let cell_reference_count = CompactU64::parse(reader)?.value(); - - declarations.push(ObjectGroupDeclaration::Blob { - object_id, - blob_id, - partition_id, - object_reference_count, - cell_reference_count, - }) - } - _ => { - return Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object type: {:x}", object_header.object_type).into(), - ) - .into()) - } - } - } - - ObjectHeader::try_parse_end_8(reader, ObjectType::ObjectGroupDeclaration)?; - - Ok(declarations) - } - - fn parse_object_group_metadata(reader: Reader) -> Result> { - let mut declarations = vec![]; - - loop { - if ObjectHeader::has_end_8(reader, ObjectType::ObjectGroupMetadataBlock)? { - break; - } - - ObjectHeader::try_parse_32(reader, ObjectType::ObjectGroupMetadata)?; - - let frequency = CompactU64::parse(reader)?; - declarations.push(ObjectGroupMetadata { - change_frequency: ObjectChangeFrequency::parse(frequency.value()), - }) - } - - ObjectHeader::try_parse_end_8(reader, ObjectType::ObjectGroupMetadataBlock)?; - - Ok(declarations) - } - - fn parse_object_group_data(reader: Reader) -> Result> { - let mut objects = vec![]; - - loop { - if ObjectHeader::has_end_8(reader, ObjectType::ObjectGroupData)? { - break; - } - - let object_header = ObjectHeader::parse(reader)?; - match object_header.object_type { - ObjectType::ObjectGroupDataExcluded => { - let group = ExGuid::parse_array(reader)?; - let cells = CellId::parse_array(reader)?; - let size = CompactU64::parse(reader)?.value(); - - objects.push(ObjectGroupData::ObjectExcluded { group, cells, size }) - } - ObjectType::ObjectGroupDataObject => { - let group = ExGuid::parse_array(reader)?; - let cells = CellId::parse_array(reader)?; - let data = BinaryItem::parse(reader)?.value(); - - objects.push(ObjectGroupData::Object { group, cells, data }) - } - ObjectType::ObjectGroupBlobReference => { - let references = ExGuid::parse_array(reader)?; - let cells = CellId::parse_array(reader)?; - let blob = ExGuid::parse(reader)?; - - objects.push(ObjectGroupData::BlobReference { - objects: references, - cells, - blob, - }) - } - _ => { - return Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object type: {:x}", object_header.object_type).into(), - ) - .into()) - } - } - } - - ObjectHeader::try_parse_end_8(reader, ObjectType::ObjectGroupData)?; - - Ok(objects) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data_element/revision_manifest.rs b/packages/onenote-converter/src/parser/fsshttpb/data_element/revision_manifest.rs deleted file mode 100644 index c7de3f2cc35..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data_element/revision_manifest.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::DataElement; -use crate::parser::Reader; - -/// A revision manifest. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.5] -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.5]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/eb3351db-8626-4804-a35b-f3eeda13c74d -#[derive(Debug)] -pub(crate) struct RevisionManifest { - pub(crate) rev_id: ExGuid, - pub(crate) base_rev_id: ExGuid, - pub(crate) root_declare: Vec, - pub(crate) group_references: Vec, -} - -/// A revision manifest root declaration. -#[derive(Debug)] -pub(crate) struct RevisionManifestRootDeclare { - pub(crate) root_id: ExGuid, - pub(crate) object_id: ExGuid, -} - -impl RevisionManifestRootDeclare { - fn parse(reader: Reader) -> Result { - let root_id = ExGuid::parse(reader)?; - let object_id = ExGuid::parse(reader)?; - - Ok(RevisionManifestRootDeclare { root_id, object_id }) - } -} - -impl DataElement { - pub(crate) fn parse_revision_manifest(reader: Reader) -> Result { - ObjectHeader::try_parse_16(reader, ObjectType::RevisionManifest)?; - - let rev_id = ExGuid::parse(reader)?; - let base_rev_id = ExGuid::parse(reader)?; - - let mut root_declare = vec![]; - let mut group_references = vec![]; - - loop { - if ObjectHeader::has_end_8(reader, ObjectType::DataElement)? { - break; - } - - let object_header = ObjectHeader::parse_16(reader)?; - - match object_header.object_type { - ObjectType::RevisionManifestRoot => { - root_declare.push(RevisionManifestRootDeclare::parse(reader)?) - } - ObjectType::RevisionManifestGroupReference => { - group_references.push(ExGuid::parse(reader)?) - } - _ => { - return Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object type: {:x}", object_header.object_type).into(), - ) - .into()) - } - } - } - - ObjectHeader::try_parse_end_8(reader, ObjectType::DataElement)?; - - let manifest = RevisionManifest { - rev_id, - base_rev_id, - root_declare, - group_references, - }; - - Ok(manifest) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data_element/storage_index.rs b/packages/onenote-converter/src/parser/fsshttpb/data_element/storage_index.rs deleted file mode 100644 index e29b8975bab..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data_element/storage_index.rs +++ /dev/null @@ -1,142 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::cell_id::CellId; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::serial_number::SerialNumber; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::DataElement; -use crate::parser::Reader; -use std::collections::HashMap; - -/// A storage index. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.2] -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.2]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/f5724986-bd0f-488d-9b85-7d5f954d8e9a -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct StorageIndex { - pub(crate) manifest_mappings: Vec, - pub(crate) cell_mappings: HashMap, - pub(crate) revision_mappings: HashMap, -} - -impl StorageIndex { - pub(crate) fn find_cell_mapping_id(&self, cell_id: CellId) -> Option { - self.cell_mappings.get(&cell_id).map(|mapping| mapping.id) - } - - pub(crate) fn find_revision_mapping_id(&self, id: ExGuid) -> Option { - self.revision_mappings - .get(&id) - .map(|mapping| mapping.revision_mapping) - } -} - -/// A storage indexes manifest mapping. -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct StorageIndexManifestMapping { - pub(crate) mapping_id: ExGuid, - pub(crate) serial: SerialNumber, -} - -/// A storage indexes cell mapping. -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct StorageIndexCellMapping { - pub(crate) cell_id: CellId, - pub(crate) id: ExGuid, - pub(crate) serial: SerialNumber, -} - -/// A storage indexes revision mapping. -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct StorageIndexRevisionMapping { - pub(crate) revision_mapping: ExGuid, - pub(crate) serial: SerialNumber, -} - -impl DataElement { - pub(crate) fn parse_storage_index(reader: Reader) -> Result { - let mut manifest_mappings = vec![]; - let mut cell_mappings = HashMap::new(); - let mut revision_mappings = HashMap::new(); - - loop { - if ObjectHeader::has_end_8(reader, ObjectType::DataElement)? { - break; - } - - let object_header = ObjectHeader::parse_16(reader)?; - match object_header.object_type { - ObjectType::StorageIndexManifestMapping => { - manifest_mappings.push(Self::parse_storage_index_manifest_mapping(reader)?) - } - ObjectType::StorageIndexCellMapping => { - let (id, mapping) = Self::parse_storage_index_cell_mapping(reader)?; - - cell_mappings.insert(id, mapping); - } - ObjectType::StorageIndexRevisionMapping => { - let (id, mapping) = Self::parse_storage_index_revision_mapping(reader)?; - - revision_mappings.insert(id, mapping); - } - _ => { - return Err(ErrorKind::MalformedFssHttpBData( - format!("unexpected object type: {:x}", object_header.object_type).into(), - ) - .into()) - } - } - } - - ObjectHeader::try_parse_end_8(reader, ObjectType::DataElement)?; - - Ok(StorageIndex { - manifest_mappings, - cell_mappings, - revision_mappings, - }) - } - - fn parse_storage_index_manifest_mapping(reader: Reader) -> Result { - let mapping_id = ExGuid::parse(reader)?; - let serial = SerialNumber::parse(reader)?; - - Ok(StorageIndexManifestMapping { mapping_id, serial }) - } - - fn parse_storage_index_cell_mapping( - reader: Reader, - ) -> Result<(CellId, StorageIndexCellMapping)> { - let cell_id = CellId::parse(reader)?; - let id = ExGuid::parse(reader)?; - let serial = SerialNumber::parse(reader)?; - - let mapping = StorageIndexCellMapping { - cell_id, - id, - serial, - }; - - Ok((cell_id, mapping)) - } - - fn parse_storage_index_revision_mapping( - reader: Reader, - ) -> Result<(ExGuid, StorageIndexRevisionMapping)> { - let id = ExGuid::parse(reader)?; - let revision_mapping = ExGuid::parse(reader)?; - let serial = SerialNumber::parse(reader)?; - - let mapping = StorageIndexRevisionMapping { - revision_mapping, - serial, - }; - - Ok((id, mapping)) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/data_element/storage_manifest.rs b/packages/onenote-converter/src/parser/fsshttpb/data_element/storage_manifest.rs deleted file mode 100644 index dd27b6f03dc..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/data_element/storage_manifest.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::parser::errors::Result; -use crate::parser::fsshttpb::data::cell_id::CellId; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::DataElement; -use crate::parser::shared::guid::Guid; -use crate::parser::Reader; -use std::collections::HashMap; - -/// A storage manifest. -/// -/// See [\[MS-FSSHTTPB\] 2.2.1.12.3] -/// -/// [\[MS-FSSHTTPB\] 2.2.1.12.3]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/a681199b-45f3-4378-b929-fb13e674ac5c -#[derive(Debug)] -pub(crate) struct StorageManifest { - pub(crate) id: Guid, - pub(crate) roots: HashMap, -} - -impl DataElement { - pub(crate) fn parse_storage_manifest(reader: Reader) -> Result { - ObjectHeader::try_parse_16(reader, ObjectType::StorageManifest)?; - - let id = Guid::parse(reader)?; - - let mut roots = HashMap::new(); - - loop { - if ObjectHeader::has_end_8(reader, ObjectType::DataElement)? { - break; - } - - ObjectHeader::try_parse_16(reader, ObjectType::StorageManifestRoot)?; - - let root_manifest = ExGuid::parse(reader)?; - let cell = CellId::parse(reader)?; - - roots.insert(root_manifest, cell); - } - - ObjectHeader::try_parse_end_8(reader, ObjectType::DataElement)?; - - Ok(StorageManifest { id, roots }) - } -} diff --git a/packages/onenote-converter/src/parser/fsshttpb/mod.rs b/packages/onenote-converter/src/parser/fsshttpb/mod.rs deleted file mode 100644 index fc55774d7ff..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! The FSSHTTP binary packaging format. -//! -//! This is the lowest level of the OneNote file format as the FSSHTTPB format specifies how -//! objects and revisions are stored in a binary file. -//! -//! See [\[MS-FSSHTTPB\]] -//! -//! [\[MS-FSSHTTPB\]]: https://docs.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-fsshttpb/f59fc37d-2232-4b14-baac-25f98e9e7b5a - -pub(crate) mod data; -pub(crate) mod data_element; -pub(crate) mod packaging; diff --git a/packages/onenote-converter/src/parser/fsshttpb/packaging.rs b/packages/onenote-converter/src/parser/fsshttpb/packaging.rs deleted file mode 100644 index 6131d066206..00000000000 --- a/packages/onenote-converter/src/parser/fsshttpb/packaging.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::fsshttpb::data::object_types::ObjectType; -use crate::parser::fsshttpb::data::stream_object::ObjectHeader; -use crate::parser::fsshttpb::data_element::DataElementPackage; -use crate::parser::shared::guid::Guid; -use crate::parser::Reader; - -/// A OneNote file packaged in FSSHTTPB format. -/// -/// See [\[MS-ONESTORE\] 2.8.1] -/// -/// [\[MS-ONESTORE\] 2.8.1]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-onestore/a2f046ea-109a-49c4-912d-dc2888cf0565 -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct OneStorePackaging { - pub(crate) file_type: Guid, - pub(crate) file: Guid, - pub(crate) legacy_file_version: Guid, - pub(crate) file_format: Guid, - pub(crate) storage_index: ExGuid, - pub(crate) cell_schema: Guid, - pub(crate) data_element_package: DataElementPackage, -} - -impl OneStorePackaging { - pub(crate) fn parse(reader: Reader) -> Result { - let file_type = Guid::parse(reader)?; - let file = Guid::parse(reader)?; - let legacy_file_version = Guid::parse(reader)?; - let file_format = Guid::parse(reader)?; - - if file != legacy_file_version { - return Err( - ErrorKind::MalformedOneStoreData("not a legacy OneStore file".into()).into(), - ); - } - - if reader.get_u32()? != 0 { - return Err(ErrorKind::MalformedFssHttpBData("invalid padding data".into()).into()); - } - - ObjectHeader::try_parse_32(reader, ObjectType::OneNotePackaging)?; - - let storage_index = ExGuid::parse(reader)?; - let cell_schema = Guid::parse(reader)?; - - let data_element_package = DataElementPackage::parse(reader)?; - - ObjectHeader::try_parse_end_16(reader, ObjectType::OneNotePackaging)?; - - Ok(OneStorePackaging { - file_type, - file, - legacy_file_version, - file_format, - storage_index, - cell_schema, - data_element_package, - }) - } -} diff --git a/packages/onenote-converter/src/parser/macros.rs b/packages/onenote-converter/src/parser/macros.rs deleted file mode 100644 index 7d505abe9db..00000000000 --- a/packages/onenote-converter/src/parser/macros.rs +++ /dev/null @@ -1,51 +0,0 @@ -macro_rules! guid { - ({ $p0:tt - $p1:tt - $p2:tt - $p3:tt - $p4:tt }) => { - crate::parser::shared::guid::Guid::from_str(concat!( - stringify!($p0), - '-', - stringify!($p1), - '-', - stringify!($p2), - '-', - stringify!($p3), - '-', - stringify!($p4), - )) - .unwrap() - }; -} - -macro_rules! exguid { - ({$guid:tt , $n:literal}) => { - crate::parser::fsshttpb::data::exguid::ExGuid::from_guid(guid!($guid), $n) - }; -} - -#[cfg(test)] -mod test { - use crate::parser::fsshttpb::data::exguid::ExGuid; - use crate::parser::shared::guid::Guid; - - #[test] - fn parse_guid() { - let guid = guid!({ 1A5A319C - C26B - 41AA - B9C5 - 9BD8C44E07D4 }); - - assert_eq!( - guid, - Guid::from_str("1A5A319C-C26B-41AA-B9C5-9BD8C44E07D4").unwrap() - ); - } - - #[test] - fn parse_exguid() { - let guid = exguid!({{1A5A319C-C26B-41AA-B9C5-9BD8C44E07D4}, 1}); - - assert_eq!( - guid, - ExGuid::from_guid( - Guid::from_str("1A5A319C-C26B-41AA-B9C5-9BD8C44E07D4").unwrap(), - 1 - ) - ); - } -} diff --git a/packages/onenote-converter/src/parser/mod.rs b/packages/onenote-converter/src/parser/mod.rs deleted file mode 100644 index 367cce87d3d..00000000000 --- a/packages/onenote-converter/src/parser/mod.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! A OneNote file parser. - -#![warn(missing_docs)] -#![deny(unused_must_use)] -pub mod errors; -mod fsshttpb; -#[macro_use] -mod macros; -mod one; -mod onenote; -mod onestore; -mod reader; -mod shared; -mod utils; - -pub(crate) type Reader<'a, 'b> = &'b mut crate::parser::reader::Reader<'a>; - -pub use onenote::Parser; - -/// The data that represents a OneNote notebook. -pub mod notebook { - pub use crate::parser::onenote::notebook::Notebook; -} - -/// The data that represents a OneNote section. -pub mod section { - pub use crate::parser::onenote::section::{Section, SectionEntry}; -} - -/// The data that represents a OneNote page. -pub mod page { - pub use crate::parser::onenote::page::Page; - pub use crate::parser::onenote::page_content::PageContent; -} - -/// The data that represents the contents of a OneNote section. -pub mod contents { - pub use crate::parser::onenote::content::Content; - pub use crate::parser::onenote::embedded_file::EmbeddedFile; - pub use crate::parser::onenote::image::Image; - pub use crate::parser::onenote::ink::{Ink, InkBoundingBox, InkPoint, InkStroke}; - pub use crate::parser::onenote::list::List; - pub use crate::parser::onenote::note_tag::NoteTag; - pub use crate::parser::onenote::outline::{Outline, OutlineElement, OutlineItem}; - pub use crate::parser::onenote::rich_text::{EmbeddedObject, RichText}; - pub use crate::parser::onenote::table::{Table, TableCell}; -} - -/// Collection of properties used by the OneNote file format. -pub mod property { - /// Properties related to multiple types of objects. - pub mod common { - pub use crate::parser::one::property::color::Color; - pub use crate::parser::one::property::color_ref::ColorRef; - } - - /// Properties related to embedded files. - pub mod embedded_file { - pub use crate::parser::one::property::file_type::FileType; - } - - /// Properties related to note tags. - pub mod note_tag { - pub use crate::parser::one::property::note_tag::ActionItemStatus; - pub use crate::parser::one::property::note_tag_shape::NoteTagShape; - } - - /// Properties related to rich-text content. - pub mod rich_text { - pub use crate::parser::one::property::paragraph_alignment::ParagraphAlignment; - pub use crate::parser::onenote::rich_text::ParagraphStyling; - } -} diff --git a/packages/onenote-converter/src/parser/one/mod.rs b/packages/onenote-converter/src/parser/one/mod.rs deleted file mode 100644 index 3789d9c8bf7..00000000000 --- a/packages/onenote-converter/src/parser/one/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! The OneNote file format. -//! -//! This module implements parsing OneNote objects from a OneNote revision store (see `onestore/`). -//! It defines the types of objects we can parse along with their properties. -//! -//! See [\[MS-ONE\]] -//! -//! [\[MS-ONE\]]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/73d22548-a613-4350-8c23-07d15576be50 - -pub(crate) mod property; -pub(crate) mod property_set; diff --git a/packages/onenote-converter/src/parser/one/property/author.rs b/packages/onenote-converter/src/parser/one/property/author.rs deleted file mode 100644 index edf48b5251f..00000000000 --- a/packages/onenote-converter/src/parser/one/property/author.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::parser::errors::Result; -use crate::parser::one::property::{simple, PropertyType}; -use crate::parser::onestore::object::Object; - -/// The author of an object. -/// -/// See [\[MS-ONE\] 2.2.67] -/// -/// [\[MS-ONE\] 2.2.67]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/db06251b-b672-4c9b-8ba5-d948caaa3edd -#[derive(Debug)] -pub(crate) struct Author(String); - -impl Author { - pub(crate) fn into_value(self) -> String { - self.0 - } - - pub(crate) fn parse(object: &Object) -> Result> { - Ok(simple::parse_string(PropertyType::Author, object)?.map(Author)) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/charset.rs b/packages/onenote-converter/src/parser/one/property/charset.rs deleted file mode 100644 index 1700d776724..00000000000 --- a/packages/onenote-converter/src/parser/one/property/charset.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// A charset representation. -/// -/// See [\[MS-ONE\] 2.3.55]. -/// -/// [\[MS-ONE\] 2.3.55]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/64e2db6e-6eeb-443c-9ccf-0f72b37ba411 -#[allow(missing_docs)] -#[derive(Debug, Copy, Clone)] -pub enum Charset { - Ansi, - Default, - Symbol, - Mac, - ShiftJis, - Hangul, - Johab, - Gb2312, - ChineseBig5, - Greek, - Turkish, - Vietnamese, - Hebrew, - Arabic, - Baltic, - Russian, - Thai, - EastEurope, - Oem, -} - -impl Charset { - pub(crate) fn parse(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value - .to_u8() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("charset is not a u8".into()))?, - None => return Ok(None), - }; - - let charset = match value { - 0 => Charset::Ansi, - 1 => Charset::Default, - 2 => Charset::Symbol, - 77 => Charset::Mac, - 128 => Charset::ShiftJis, - 129 => Charset::Hangul, - 130 => Charset::Johab, - 134 => Charset::Gb2312, - 136 => Charset::ChineseBig5, - 161 => Charset::Greek, - 162 => Charset::Turkish, - 163 => Charset::Vietnamese, - 177 => Charset::Hebrew, - 178 => Charset::Arabic, - 186 => Charset::Baltic, - 204 => Charset::Russian, - 222 => Charset::Thai, - 238 => Charset::EastEurope, - 255 => Charset::Oem, - _ => { - return Err(ErrorKind::MalformedOneNoteFileData( - format!("invalid charset: {}", value).into(), - ) - .into()) - } - }; - - Ok(Some(charset)) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/color.rs b/packages/onenote-converter/src/parser/one/property/color.rs deleted file mode 100644 index 3bc3385709c..00000000000 --- a/packages/onenote-converter/src/parser/one/property/color.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// A RGBA color value. -/// -/// See [\[MS-ONE\] 2.2.7] -/// -/// [\[MS-ONE\] 2.2.7]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/6e4a87f9-18f0-4ad6-bc7d-0f326d61e136 -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Color { - alpha: u8, - r: u8, - g: u8, - b: u8, -} - -impl Color { - /// The color's transparency value. - pub fn alpha(&self) -> u8 { - self.alpha - } - - /// The color's red value. - pub fn r(&self) -> u8 { - self.r - } - - /// The color's green value. - pub fn g(&self) -> u8 { - self.g - } - - /// The color's blue value. - pub fn b(&self) -> u8 { - self.b - } -} - -impl Color { - pub(crate) fn parse(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value - .to_u32() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("color is not a u32".into()))?, - None => return Ok(None), - }; - - let bytes = value.to_le_bytes(); - - Ok(Some(Color { - alpha: 255 - bytes[3], - r: bytes[0], - g: bytes[1], - b: bytes[2], - })) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/color_ref.rs b/packages/onenote-converter/src/parser/one/property/color_ref.rs deleted file mode 100644 index 2f74bec1a1e..00000000000 --- a/packages/onenote-converter/src/parser/one/property/color_ref.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// An RGB color value. -/// -/// See [\[MS-ONE\] 2.2.8] -/// -/// [\[MS-ONE\] 2.2.8]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/3796cb27-7ec3-4dc9-b43e-7c31cc5b765d -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub enum ColorRef { - /// Determined by the application. - Auto, - - /// A manually specified color - Manual { - /// The color's red value. - r: u8, - /// The color's green value. - g: u8, - /// The color's blue value - b: u8, - }, -} - -impl ColorRef { - pub(crate) fn parse(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value.to_u32().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("color ref is not a u32".into()) - })?, - None => return Ok(None), - }; - - let bytes = value.to_le_bytes(); - - let color = match bytes[3] { - 0xFF => ColorRef::Auto, - 0x00 => ColorRef::Manual { - r: bytes[0], - g: bytes[1], - b: bytes[2], - }, - _ => { - return Err(ErrorKind::MalformedOneNoteFileData( - format!("invalid color ref: 0x{:08X}", value).into(), - ) - .into()) - } - }; - - Ok(Some(color)) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/file_type.rs b/packages/onenote-converter/src/parser/one/property/file_type.rs deleted file mode 100644 index 7cbd841cc69..00000000000 --- a/packages/onenote-converter/src/parser/one/property/file_type.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// An embedded file's file type. -/// -/// See [\[MS-ONE\] 2.3.62]. -/// -/// [\[MS-ONE\] 2.3.62]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/112836a0-ed3b-4be1-bc4b-49f0f7b02295 -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub enum FileType { - /// Unknown - Unknown, - - /// An audio file. - Audio, - - /// A video file. - Video, -} - -impl FileType { - pub(crate) fn parse(object: &Object) -> Result { - let value = match object.props().get(PropertyType::IRecordMedia) { - Some(value) => value.to_u32().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("file type status is not a u32".into()) - })?, - None => return Ok(FileType::Unknown), - }; - - let file_type = match value { - 1 => FileType::Audio, - 2 => FileType::Video, - _ => { - return Err(ErrorKind::MalformedOneNoteFileData( - format!("invalid file type: {}", value).into(), - ) - .into()) - } - }; - - Ok(file_type) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/ink_dimensions.rs b/packages/onenote-converter/src/parser/one/property/ink_dimensions.rs deleted file mode 100644 index 549bd0fcdd7..00000000000 --- a/packages/onenote-converter/src/parser/one/property/ink_dimensions.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; -use crate::parser::reader::Reader; -use crate::parser::shared::guid::Guid; - -/// The dimensions (X or Y) for an ink stoke with lower and upper limits. -#[allow(dead_code)] -pub(crate) struct InkDimension { - pub(crate) id: Guid, - pub(crate) limit_lower: i32, - pub(crate) limit_upper: i32, -} - -impl InkDimension { - pub(crate) fn parse(prop_type: PropertyType, object: &Object) -> Result> { - let data = match object.props().get(prop_type) { - Some(value) => value.to_vec().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("ink dimensions is not a vec".into()) - })?, - None => return Ok(Vec::new()), - }; - - data.chunks_exact(32) - .map(InkDimension::parse_entry) - .collect::>>() - } - - fn parse_entry(data: &[u8]) -> Result { - let mut reader = Reader::new(data); - let id = Guid::parse(&mut reader)?; - let limit_lower = reader.get_u32()? as i32; - let limit_upper = reader.get_u32()? as i32; - - Ok(InkDimension { - id, - limit_lower, - limit_upper, - }) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/layout_alignment.rs b/packages/onenote-converter/src/parser/one/property/layout_alignment.rs deleted file mode 100644 index 26213d6ee4c..00000000000 --- a/packages/onenote-converter/src/parser/one/property/layout_alignment.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// A layout alignment specification. -/// -/// See [\[MS-ONE\] 2.3.2] -/// -/// [\[MS-ONE\] 2.3.2]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/bd99face-5839-4276-863d-a4f2cbb81246 -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub struct LayoutAlignment { - alignment_horizontal: HorizontalAlignment, - alignment_margin_horizontal: HorizontalAlignmentMargin, - alignment_vertical: VerticalAlignment, - alignment_margin_vertical: VerticalAlignmentMargin, -} - -impl LayoutAlignment { - pub fn alignment_horizontal(&self) -> HorizontalAlignment { - self.alignment_horizontal - } - - pub fn alignment_margin_horizontal(&self) -> HorizontalAlignmentMargin { - self.alignment_margin_horizontal - } - - pub fn alignment_vertical(&self) -> VerticalAlignment { - self.alignment_vertical - } - - pub fn alignment_margin_vertical(&self) -> VerticalAlignmentMargin { - self.alignment_margin_vertical - } -} - -impl LayoutAlignment { - pub(crate) fn parse( - prop_type: PropertyType, - object: &Object, - ) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value.to_u32().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("layout alignment is not a u32".into()) - })?, - None => return Ok(None), - }; - - if (value >> 31) & 0x1 != 0 { - return Ok(None); - } - - let alignment_horizontal = HorizontalAlignment::parse(value & 0x7)?; - let alignment_margin_horizontal = HorizontalAlignmentMargin::parse((value >> 3) & 0x1)?; - let alignment_vertical = VerticalAlignment::parse((value >> 16) & 0x1)?; - let alignment_margin_vertical = VerticalAlignmentMargin::parse((value >> 19) & 0x1)?; - - Ok(Some(LayoutAlignment { - alignment_horizontal, - alignment_margin_horizontal, - alignment_vertical, - alignment_margin_vertical, - })) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub enum HorizontalAlignment { - Unknown, - Left, - Center, - Right, - BiDiNormal, - BiDiReverse, -} - -impl HorizontalAlignment { - pub(crate) fn parse(value: u32) -> Result { - match value { - 0 => Ok(HorizontalAlignment::Unknown), - 1 => Ok(HorizontalAlignment::Left), - 2 => Ok(HorizontalAlignment::Center), - 3 => Ok(HorizontalAlignment::Right), - 4 => Ok(HorizontalAlignment::BiDiNormal), - 5 => Ok(HorizontalAlignment::BiDiReverse), - _ => Err(ErrorKind::MalformedOneNoteFileData( - format!("invalid horizontal alignment: {}", value).into(), - ) - .into()), - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub enum HorizontalAlignmentMargin { - Right, - Left, -} - -impl HorizontalAlignmentMargin { - pub(crate) fn parse(value: u32) -> Result { - match value { - 0 => Ok(HorizontalAlignmentMargin::Right), - 1 => Ok(HorizontalAlignmentMargin::Left), - _ => Err(ErrorKind::MalformedOneNoteFileData( - format!("invalid horizontal alignment margin: {}", value).into(), - ) - .into()), - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub enum VerticalAlignment { - Bottom, - Top, -} - -impl VerticalAlignment { - pub(crate) fn parse(value: u32) -> Result { - match value { - 0 => Ok(VerticalAlignment::Bottom), - 1 => Ok(VerticalAlignment::Top), - _ => Err(ErrorKind::MalformedOneNoteFileData( - format!("invalid vertical alignment: {}", value).into(), - ) - .into()), - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub enum VerticalAlignmentMargin { - Bottom, - Top, -} - -impl VerticalAlignmentMargin { - pub(crate) fn parse(value: u32) -> Result { - match value { - 0 => Ok(VerticalAlignmentMargin::Bottom), - 1 => Ok(VerticalAlignmentMargin::Top), - _ => Err(ErrorKind::MalformedOneNoteFileData( - format!("invalid vertical alignment margin: {}", value).into(), - ) - .into()), - } - } -} diff --git a/packages/onenote-converter/src/parser/one/property/mod.rs b/packages/onenote-converter/src/parser/one/property/mod.rs deleted file mode 100644 index 04c3a681076..00000000000 --- a/packages/onenote-converter/src/parser/one/property/mod.rs +++ /dev/null @@ -1,208 +0,0 @@ -//! The properties of OneNote objects that we can parse. -//! -//! See [\[MS-ONE\] 2.1.12] for the list of properties the OneNote file format specifies. -//! -//! [\[MS-ONE\] 2.1.12]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/e9bf7da8-7aab-4668-be5e-e0c421175e3c - -pub(crate) mod author; -pub(crate) mod charset; -pub(crate) mod color; -pub(crate) mod color_ref; -pub(crate) mod file_type; -pub(crate) mod ink_dimensions; -pub(crate) mod layout_alignment; -pub(crate) mod note_tag; -pub(crate) mod note_tag_property_status; -pub(crate) mod note_tag_shape; -pub(crate) mod object_reference; -pub(crate) mod object_space_reference; -pub(crate) mod outline_indent_distance; -pub(crate) mod page_size; -pub(crate) mod paragraph_alignment; -mod references; -pub(crate) mod simple; -pub(crate) mod time; - -#[derive(Debug, Copy, Clone, PartialEq)] -#[allow(dead_code)] -pub(crate) enum PropertyType { - ActionItemSchemaVersion = 0x0C003473, - ActionItemStatus = 0x10003470, - ActionItemType = 0x10003463, - Author = 0x1C001D75, - AuthorMostRecent = 0x20001D79, - AuthorOriginal = 0x20001D78, - BodyTextAlignment = 0x0C001C13, - Bold = 0x08001C04, - CachedTitleString = 0x1C001CF3, - CachedTitleStringFromPage = 0x1C001D3C, - CannotBeSelected = 0x08001CB2, - Charset = 0x0C001D01, - ChildGraphSpaceElementNodes = 0x2C001D63, - ColumnCount = 0x14001D58, - ConflictingUserName = 0x1C001D9E, - ContentChildNodes = 0x24001C1F, - CreationTimeStamp = 0x14001D09, - Deletable = 0x08001D0C, - DescendantsCannotBeMoved = 0x08001CF9, - DisplayedPageNumber = 0x14003480, - EditRootRtl = 0x08001C92, - ElementChildNodes = 0x24001C20, - EmbeddedFileContainer = 0x20001D9B, - EmbeddedFileName = 0x1C001D9C, - EnableHistory = 0x08001E1E, - EnforceOutlineStructure = 0x08001C91, - FileAncestorIdentityGuid = 0x1C001D95, - FileIdentityGuid = 0x1C001D94, - FileLastCodeVersionThatWroteToIt = 0x14001D99, - FileNameCrc = 0x14001D93, - Font = 0x1C001C0A, - FontColor = 0x14001C0C, - FontSize = 0x10001C0B, - HasVersionPages = 0x08003462, - Hidden = 0x08001E16, - Highlight = 0x14001C0D, - Hyperlink = 0x08001E14, - HyperlinkProtected = 0x08001E19, - IRecordMedia = 0x14001D24, - ImageAltText = 0x1C001E58, - ImageFilename = 0x1C001DD7, - ImageUploadState = 0x140034CB, - IsBackground = 0x08001D13, - IsBoilerText = 0x08001C88, - IsConflictObjectForRender = 0x08001D96, - IsConflictObjectForSelection = 0x08001DDB, - IsConflictPage = 0x08001D7C, - IsDeletedGraphSpaceContent = 0x00001DE9, - IsLayoutSizeSetByUser = 0x08001CBD, - IsReadOnly = 0x08001CDE, - IsTitleDate = 0x08001CB5, - IsTitleText = 0x08001CB4, - IsTitleTime = 0x08001C87, - Italic = 0x08001C05, - LanguageId = 0x14001C3B, - LastModifiedTime = 0x14001D7A, - LastModifiedTimeStamp = 0x18001D77, - LayoutAlignmentInParent = 0x14001C3E, - LayoutAlignmentSelf = 0x14001C84, - LayoutCollisionPriority = 0x14001CF1, - LayoutMaxHeight = 0x14001C1C, - LayoutMaxWidth = 0x14001C1B, - LayoutMinimumOutlineWidth = 0x14001CEC, - LayoutOutlineReservedWidth = 0x14001CDB, - LayoutResolveChildCollisions = 0x08001CDC, - LayoutTightAlignment = 0x08001CFF, - LayoutTightLayout = 0x08001C00, - ListFont = 0x1C001C52, - ListMsaaIndex = 0x10001D0E, - ListNodes = 0x24001C26, - ListRestart = 0x14001CB7, - ListSpacingMu = 0x14001CCB, - MathFormatting = 0x08003401, - MetaDataObjectsAboveGraphSpace = 0x24003442, - NextStyle = 0x1C00348A, - NoteTagCompleted = 0x1400346F, - NoteTagCreated = 0x1400346E, - NoteTagDefinitionOid = 0x20003488, - NoteTagHighlightColor = 0x14003465, - NoteTagLabel = 0x1C003468, - NoteTagPropertyStatus = 0x14003467, - NoteTagShape = 0x10003464, - NoteTagStates = 0x04003489, - NoteTagTextColor = 0x14003466, - NotebookManagementEntityGuid = 0x1C001C30, - NumberListFormat = 0x1C001C1A, - OffsetFromParentHoriz = 0x14001C14, - OffsetFromParentVert = 0x14001C15, - OutlineElementChildLevel = 0x0C001C03, - OutlineElementRtl = 0x08001C34, - PageHeight = 0x14001C02, - PageLevel = 0x14001DFF, - PageMarginBottom = 0x14001C4D, - PageMarginLeft = 0x14001C4E, - PageMarginOriginX = 0x14001D0F, - PageMarginOriginY = 0x14001D10, - PageMarginRight = 0x14001C4F, - PageMarginTop = 0x14001C4C, - PageSize = 0x14001C8B, - PageWidth = 0x14001C01, - ParagraphAlignment = 0x0C003477, - ParagraphLineSpacingExact = 0x14003430, - ParagraphSpaceAfter = 0x1400342F, - ParagraphSpaceBefore = 0x1400342E, - ParagraphStyle = 0x2000342C, - ParagraphStyleId = 0x1C00345A, - PictureContainer = 0x20001C3F, - PictureHeight = 0x140034CE, - PictureWidth = 0x140034CD, - PortraitPage = 0x08001C8E, - ReadingOrderRtl = 0x08003476, - RgOutlineIndentDistance = 0x1C001C12, - RichEditTextLangId = 0x10001CFE, - RichEditTextUnicode = 0x1C001C22, - RowCount = 0x14001D57, - SchemaRevisionInOrderToRead = 0x14001D82, - SchemaRevisionInOrderToWrite = 0x1400348B, - SectionDisplayName = 0x1C00349B, - SourceFilepath = 0x1C001D9D, - Strikethrough = 0x08001C07, - StructureElementChildNodes = 0x24001D5F, - Subscript = 0x08001C09, - Superscript = 0x08001C08, - TableBordersVisible = 0x08001D5E, - TableColumnWidths = 0x1C001D66, - TableColumnsLocked = 0x1C001D7D, - TaskTagDueDat = 0x1400346B, - TextExtendedAscii = 0x1C003498, - TextRunData = 0x40003499, - TextRunDataObject = 0x24003458, - TextRunFormatting = 0x24001E13, - TextRunIndex = 0x1C001E12, - TextRunIsEmbeddedObject = 0x08001E22, - TopologyCreationTimeStamp = 0x18001C65, - Underline = 0x08001C06, - UnderlineType = 0x0C001E15, - VersionHistoryGraphSpaceContextNodes = 0x3400347B, - WebPictureContainer14 = 0x200034C8, - WzHyperlinkUrl = 0x1C001E20, - - // Undocumented: - TocChildren = 0x24001CF6, - FolderChildFilename = 0x1C001D6B, - NotebookElementOrderingId = 0x14001CB9, - PictureFileExtension = 0x24003424, - NoteTags = 0x40003489, - NoteTag = 0x44000811, - SectionColor = 0x14001CBE, - CellBackgroundColor = 0x14001E26, - InkBias = 0x0C00341C, - InkData = 0x20003415, - InkDimensions = 0x1C00340A, - InkPath = 0x1C00340B, - InkStrokeProperties = 0x20003409, - InkStrokes = 0x24003416, - // TODO: Fix values not being accepted as valid enum values - // InkAntialised = 0x8000340E, - // InkFitToCurve = 0x80003410, - InkIgnorePressure = 0x08003411, - InkPenTip = 0x0C003412, - InkRasterOperation = 0x0C003413, - InkTransparency = 0x0C003414, - InkHeight = 0x1400340C, - InkWidth = 0x1400340D, - InkColor = 0x1400340F, - InkScalingX = 0x14001C46, - InkScalingY = 0x14001C47, - InkBoundingBox = 0x1C003418, - EmbeddedObjectType = 0x14003457, - EmbeddedInkStartX = 0x1400349E, - EmbeddedInkStartY = 0x1400349F, - EmbeddedInkWidth = 0x140034A0, - EmbeddedInkHeight = 0x140034A1, - EmbeddedInkOffsetHoriz = 0x140034A2, - EmbeddedInkOffsetVert = 0x140034A3, - EmbeddedInkSpaceWidth = 0x14001C27, - EmbeddedInkSpaceHeight = 0x14001C28, - ImageEmbedType = 0x140035F2, - ImageEmbeddedUrl = 0x1C0035F3, -} diff --git a/packages/onenote-converter/src/parser/one/property/note_tag.rs b/packages/onenote-converter/src/parser/one/property/note_tag.rs deleted file mode 100644 index 5e610e689dd..00000000000 --- a/packages/onenote-converter/src/parser/one/property/note_tag.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// The action status of a note tag. -/// -/// See [\[MS-ONE\] 2.3.91]. -/// -/// [\[MS-ONE\] 2.3.91]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/6b516f12-8f47-40b3-9dd4-44c00aac206b -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub struct ActionItemStatus { - completed: bool, - disabled: bool, - task_tag: bool, -} - -impl ActionItemStatus { - /// Whether the checkable note tag is completed. - pub fn completed(&self) -> bool { - self.completed - } - - /// Whether the note tag is disabled. - pub fn disabled(&self) -> bool { - self.disabled - } - - /// Whether the note tag is a task tag. - pub fn task_tag(&self) -> bool { - self.task_tag - } -} - -impl ActionItemStatus { - pub(crate) fn parse(object: &Object) -> Result> { - let value = match object.props().get(PropertyType::ActionItemStatus) { - Some(value) => value.to_u16().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("action item status is not a u16".into()) - })?, - None => return Ok(None), - }; - - let completed = value & 0x1 != 0; - let disabled = (value >> 1) & 0x1 != 0; - let task_tag = (value >> 2) & 0x1 != 0; - - Ok(Some(ActionItemStatus { - completed, - disabled, - task_tag, - })) - } -} - -/// The identifier and item type of a note tag. -/// -/// See [\[MS-ONE\] 2.3.85]. -/// -/// [\[MS-ONE\] 2.3.85]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/b39a1d88-b8e1-48c6-bbfe-99ac3effe91b -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[allow(missing_docs)] -pub enum ActionItemType { - Numeric(u16), - DueToday, - DueTomorrow, - DueThisWeek, - DueNextWeek, - NoDueDate, - CustomDueDate, - Unknown, -} - -impl ActionItemType { - pub(crate) fn parse(object: &Object) -> Result> { - let value = match object.props().get(PropertyType::ActionItemType) { - Some(value) => value.to_u16().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("action item type is not a u16".into()) - })?, - None => return Ok(None), - }; - - let item_type = match value { - 0..=99 => ActionItemType::Numeric(value), - 100 => ActionItemType::DueToday, - 101 => ActionItemType::DueTomorrow, - 102 => ActionItemType::DueThisWeek, - 103 => ActionItemType::DueNextWeek, - 104 => ActionItemType::NoDueDate, - 105 => ActionItemType::CustomDueDate, - _ => ActionItemType::Unknown, - }; - - Ok(Some(item_type)) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/note_tag_property_status.rs b/packages/onenote-converter/src/parser/one/property/note_tag_property_status.rs deleted file mode 100644 index 4244036d7ba..00000000000 --- a/packages/onenote-converter/src/parser/one/property/note_tag_property_status.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// The status of a note tag. -/// -/// See [\[MS-ONE\] 2.3.87]. -/// -/// [\[MS-ONE\] 2.3.87]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/24274836-ec41-4fee-913f-225d65ac457c -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub struct NoteTagPropertyStatus { - has_label: bool, - has_font_color: bool, - has_highlight_color: bool, - has_icon: bool, - due_today: bool, - due_tomorrow: bool, - due_this_week: bool, - due_next_week: bool, - due_later: bool, - due_custom: bool, -} - -impl NoteTagPropertyStatus { - /// Whether the note tag has a labe. - pub fn has_label(&self) -> bool { - self.has_label - } - - /// Whether the note tag has a font color. - pub fn has_font_color(&self) -> bool { - self.has_font_color - } - - /// Whether the note tag has a text highlight color. - pub fn has_highlight_color(&self) -> bool { - self.has_highlight_color - } - - /// Whether the note tag has an icon. - pub fn has_icon(&self) -> bool { - self.has_icon - } - - /// Whether the note tag has is due today. - pub fn due_today(&self) -> bool { - self.due_today - } - - /// Whether the note tag has is due tomorrow. - pub fn due_tomorrow(&self) -> bool { - self.due_tomorrow - } - - /// Whether the note tag has is due this week. - pub fn due_this_week(&self) -> bool { - self.due_this_week - } - - /// Whether the note tag has is due next week. - pub fn due_next_week(&self) -> bool { - self.due_next_week - } - - /// Whether the note tag has is due later. - pub fn due_later(&self) -> bool { - self.due_later - } - - /// Whether the note tag has is due at a custom date. - pub fn due_custom(&self) -> bool { - self.due_custom - } -} - -impl NoteTagPropertyStatus { - pub(crate) fn parse(object: &Object) -> Result> { - let value = match object.props().get(PropertyType::NoteTagPropertyStatus) { - Some(value) => value.to_u32().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("note tag property status is not a u32".into()) - })?, - None => return Ok(None), - }; - - let status = NoteTagPropertyStatus { - has_label: value & 0x1 != 0, - has_font_color: (value >> 1) & 0x1 != 0, - has_highlight_color: (value >> 2) & 0x1 != 0, - has_icon: (value >> 3) & 0x1 != 0, - due_today: (value >> 6) & 0x1 != 0, - due_tomorrow: (value >> 7) & 0x1 != 0, - due_this_week: (value >> 8) & 0x1 != 0, - due_next_week: (value >> 9) & 0x1 != 0, - due_later: (value >> 10) & 0x1 != 0, - due_custom: (value >> 11) & 0x1 != 0, - }; - - Ok(Some(status)) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/note_tag_shape.rs b/packages/onenote-converter/src/parser/one/property/note_tag_shape.rs deleted file mode 100644 index 00893a4a908..00000000000 --- a/packages/onenote-converter/src/parser/one/property/note_tag_shape.rs +++ /dev/null @@ -1,344 +0,0 @@ -/// The shape of a note tag icon. -/// -/// See [\[MS-ONE\] 2.3.86]. -/// -/// [\[MS-ONE\] 2.3.86]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/aa5c7aba-d5e4-4bf8-b265-9100eeb9a7a7 -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[allow(missing_docs)] -pub enum NoteTagShape { - NoIcon, - GreenCheckBox, - YellowCheckBox, - BlueCheckBox, - GreenStarCheckBox, - YellowStarCheckBox, - BlueStarCheckBox, - GreenExclamationCheckBox, - YellowExclamationCheckBox, - BlueExclamationCheckBox, - GreenRightArrowCheckBox, - YellowRightArrowCheckBox, - BlueRightArrowCheckBox, - YellowStar, - BlueFollowUpFlag, - QuestionMark, - BlueRightArrow, - HighPriority, - ContactInformation, - Meeting, - TimeSensitive, - LightBulb, - Pushpin, - Home, - CommentBubble, - SmilingFace, - AwardRibbon, - YellowKey, - BlueCheckBox1, - BlueCircle1, - BlueCheckBox2, - BlueCircle2, - BlueCheckBox3, - BlueCircle3, - BlueEightPointStar, - BlueCheckMark, - BlueCircle, - BlueDownArrow, - BlueLeftArrow, - BlueSolidTarget, - BlueStar, - BlueSun, - BlueTarget, - BlueTriangle, - BlueUmbrella, - BlueUpArrow, - BlueXWithDots, - BlueX, - GreenCheckBox1, - GreenCircle1, - GreenCheckBox2, - GreenCircle2, - GreenCheckBox3, - GreenCircle3, - GreenEightPointStar, - GreenCheckMark, - GreenCircle, - GreenDownArrow, - GreenLeftArrow, - GreenRightArrow, - GreenSolidArrow, - GreenStar, - GreenSun, - GreenTarget, - GreenTriangle, - GreenUmbrella, - GreenUpArrow, - GreenXWithDots, - GreenX, - YellowCheckBox1, - YellowCircle1, - YellowCheckBox2, - YellowCircle2, - YellowCheckBox3, - YellowCircle3, - YellowEightPointStar, - YellowCheckMark, - YellowCircle, - YellowDownArrow, - YellowLeftArrow, - YellowRightArrow, - YellowSolidTarget, - YellowSun, - YellowTarget, - YellowTriangle, - YellowUmbrella, - YellowUpArrow, - YellowXWithDots, - YellowX, - FollowUpTodayFlag, - FollowUpTomorrowFlag, - FollowUpThisWeekFlag, - FollowUpNextWeekFlag, - NoFollowUpDateFlag, - BluePersonCheckBox, - YellowPersonCheckBox, - GreenPersonCheckBox, - BlueFlagCheckBox, - RedFlagCheckBox, - GreenFlagCheckBox, - RedSquare, - YellowSquare, - BlueSquare, - GreenSquare, - OrangeSquare, - PinkSquare, - EMailMessage, - ClosedEnvelope, - OpenEnvelope, - MobilePhone, - TelephoneWithClock, - QuestionBalloon, - PaperClip, - FrowningFace, - InstantMessagingContactPerson, - PersonWithExclamationMark, - TwoPeople, - ReminderBell, - Contact, - RoseOnAStem, - CalendarDateWithClock, - MusicalNote, - MovieClip, - QuotationMark, - Globe, - HyperlinkGlobe, - Laptop, - Plane, - Car, - Binoculars, - PresentationSlide, - Padlock, - OpenBook, - NotebookWithClock, - BlankPaperWithLines, - Research, - Pen, - DollarSign, - CoinsWithAWindowBackdrop, - ScheduledTask, - LightningBolt, - Cloud, - Heart, - Sunflower, -} - -impl NoteTagShape { - pub(crate) fn parse(value: u16) -> NoteTagShape { - match value { - 0 => NoteTagShape::NoIcon, - 1 => NoteTagShape::GreenCheckBox, - 2 => NoteTagShape::YellowCheckBox, - 3 => NoteTagShape::BlueCheckBox, - 4 => NoteTagShape::GreenStarCheckBox, - 5 => NoteTagShape::YellowStarCheckBox, - 6 => NoteTagShape::BlueStarCheckBox, - 7 => NoteTagShape::GreenExclamationCheckBox, - 8 => NoteTagShape::YellowExclamationCheckBox, - 9 => NoteTagShape::BlueExclamationCheckBox, - 10 => NoteTagShape::GreenRightArrowCheckBox, - 11 => NoteTagShape::YellowRightArrowCheckBox, - 12 => NoteTagShape::BlueRightArrowCheckBox, - 13 => NoteTagShape::YellowStar, - 14 => NoteTagShape::BlueFollowUpFlag, - 15 => NoteTagShape::QuestionMark, - 16 => NoteTagShape::BlueRightArrow, - 17 => NoteTagShape::HighPriority, - 18 => NoteTagShape::ContactInformation, - 19 => NoteTagShape::Meeting, - 20 => NoteTagShape::TimeSensitive, - 21 => NoteTagShape::LightBulb, - 22 => NoteTagShape::Pushpin, - 23 => NoteTagShape::Home, - 24 => NoteTagShape::CommentBubble, - 25 => NoteTagShape::SmilingFace, - 26 => NoteTagShape::AwardRibbon, - 27 => NoteTagShape::YellowKey, - 28 => NoteTagShape::BlueCheckBox1, - 29 => NoteTagShape::BlueCircle1, - 30 => NoteTagShape::BlueCheckBox2, - 31 => NoteTagShape::BlueCircle2, - 32 => NoteTagShape::BlueCheckBox3, - 33 => NoteTagShape::BlueCircle3, - 34 => NoteTagShape::BlueEightPointStar, - 35 => NoteTagShape::BlueCheckMark, - 36 => NoteTagShape::BlueCircle, - 37 => NoteTagShape::BlueDownArrow, - 38 => NoteTagShape::BlueLeftArrow, - 39 => NoteTagShape::BlueSolidTarget, - 40 => NoteTagShape::BlueStar, - 41 => NoteTagShape::BlueSun, - 42 => NoteTagShape::BlueTarget, - 43 => NoteTagShape::BlueTriangle, - 44 => NoteTagShape::BlueUmbrella, - 45 => NoteTagShape::BlueUpArrow, - 46 => NoteTagShape::BlueXWithDots, - 47 => NoteTagShape::BlueX, - 48 => NoteTagShape::GreenCheckBox1, - 49 => NoteTagShape::GreenCircle1, - 50 => NoteTagShape::GreenCheckBox2, - 51 => NoteTagShape::GreenCircle2, - 52 => NoteTagShape::GreenCheckBox3, - 53 => NoteTagShape::GreenCircle3, - 54 => NoteTagShape::GreenEightPointStar, - 55 => NoteTagShape::GreenCheckMark, - 56 => NoteTagShape::GreenCircle, - 57 => NoteTagShape::GreenDownArrow, - 58 => NoteTagShape::GreenLeftArrow, - 59 => NoteTagShape::GreenRightArrow, - 60 => NoteTagShape::GreenSolidArrow, - 61 => NoteTagShape::GreenStar, - 62 => NoteTagShape::GreenSun, - 63 => NoteTagShape::GreenTarget, - 64 => NoteTagShape::GreenTriangle, - 65 => NoteTagShape::GreenUmbrella, - 66 => NoteTagShape::GreenUpArrow, - 67 => NoteTagShape::GreenXWithDots, - 68 => NoteTagShape::GreenX, - 69 => NoteTagShape::YellowCheckBox1, - 70 => NoteTagShape::YellowCircle1, - 71 => NoteTagShape::YellowCheckBox2, - 72 => NoteTagShape::YellowCircle2, - 73 => NoteTagShape::YellowCheckBox3, - 74 => NoteTagShape::YellowCircle3, - 75 => NoteTagShape::YellowEightPointStar, - 76 => NoteTagShape::YellowCheckMark, - 77 => NoteTagShape::YellowCircle, - 78 => NoteTagShape::YellowDownArrow, - 79 => NoteTagShape::YellowLeftArrow, - 80 => NoteTagShape::YellowRightArrow, - 81 => NoteTagShape::YellowSolidTarget, - 82 => NoteTagShape::YellowSun, - 83 => NoteTagShape::YellowTarget, - 84 => NoteTagShape::YellowTriangle, - 85 => NoteTagShape::YellowUmbrella, - 86 => NoteTagShape::YellowUpArrow, - 87 => NoteTagShape::YellowXWithDots, - 88 => NoteTagShape::YellowX, - 89 => NoteTagShape::FollowUpTodayFlag, - 90 => NoteTagShape::FollowUpTomorrowFlag, - 91 => NoteTagShape::FollowUpThisWeekFlag, - 92 => NoteTagShape::FollowUpNextWeekFlag, - 93 => NoteTagShape::NoFollowUpDateFlag, - 94 => NoteTagShape::BluePersonCheckBox, - 95 => NoteTagShape::YellowPersonCheckBox, - 96 => NoteTagShape::GreenPersonCheckBox, - 97 => NoteTagShape::BlueFlagCheckBox, - 98 => NoteTagShape::RedFlagCheckBox, - 99 => NoteTagShape::GreenFlagCheckBox, - 100 => NoteTagShape::RedSquare, - 101 => NoteTagShape::YellowSquare, - 102 => NoteTagShape::BlueSquare, - 103 => NoteTagShape::GreenSquare, - 104 => NoteTagShape::OrangeSquare, - 105 => NoteTagShape::PinkSquare, - 106 => NoteTagShape::EMailMessage, - 107 => NoteTagShape::ClosedEnvelope, - 108 => NoteTagShape::OpenEnvelope, - 109 => NoteTagShape::MobilePhone, - 110 => NoteTagShape::TelephoneWithClock, - 111 => NoteTagShape::QuestionBalloon, - 112 => NoteTagShape::PaperClip, - 113 => NoteTagShape::FrowningFace, - 114 => NoteTagShape::InstantMessagingContactPerson, - 115 => NoteTagShape::PersonWithExclamationMark, - 116 => NoteTagShape::TwoPeople, - 117 => NoteTagShape::ReminderBell, - 118 => NoteTagShape::Contact, - 119 => NoteTagShape::RoseOnAStem, - 120 => NoteTagShape::CalendarDateWithClock, - 121 => NoteTagShape::MusicalNote, - 122 => NoteTagShape::MovieClip, - 123 => NoteTagShape::QuotationMark, - 124 => NoteTagShape::Globe, - 125 => NoteTagShape::HyperlinkGlobe, - 126 => NoteTagShape::Laptop, - 127 => NoteTagShape::Plane, - 128 => NoteTagShape::Car, - 129 => NoteTagShape::Binoculars, - 130 => NoteTagShape::PresentationSlide, - 131 => NoteTagShape::Padlock, - 132 => NoteTagShape::OpenBook, - 133 => NoteTagShape::NotebookWithClock, - 134 => NoteTagShape::BlankPaperWithLines, - 135 => NoteTagShape::Research, - 136 => NoteTagShape::Pen, - 137 => NoteTagShape::DollarSign, - 138 => NoteTagShape::CoinsWithAWindowBackdrop, - 139 => NoteTagShape::ScheduledTask, - 140 => NoteTagShape::LightningBolt, - 141 => NoteTagShape::Cloud, - 142 => NoteTagShape::Heart, - 143 => NoteTagShape::Sunflower, - _ => panic!("invalid note tag shape: {}", value), - } - } - - /// Whether the note tag icon is checkable. - pub fn is_checkable(&self) -> bool { - matches!( - self, - NoteTagShape::GreenCheckBox - | NoteTagShape::YellowCheckBox - | NoteTagShape::BlueCheckBox - | NoteTagShape::GreenStarCheckBox - | NoteTagShape::YellowStarCheckBox - | NoteTagShape::BlueStarCheckBox - | NoteTagShape::GreenExclamationCheckBox - | NoteTagShape::YellowExclamationCheckBox - | NoteTagShape::BlueExclamationCheckBox - | NoteTagShape::GreenRightArrowCheckBox - | NoteTagShape::YellowRightArrowCheckBox - | NoteTagShape::BlueRightArrowCheckBox - | NoteTagShape::BlueCheckBox1 - | NoteTagShape::BlueCheckBox2 - | NoteTagShape::BlueCheckBox3 - | NoteTagShape::GreenCheckBox1 - | NoteTagShape::GreenCheckBox2 - | NoteTagShape::GreenCheckBox3 - | NoteTagShape::YellowCheckBox1 - | NoteTagShape::YellowCheckBox2 - | NoteTagShape::YellowCheckBox3 - | NoteTagShape::FollowUpTodayFlag - | NoteTagShape::FollowUpTomorrowFlag - | NoteTagShape::FollowUpThisWeekFlag - | NoteTagShape::FollowUpNextWeekFlag - | NoteTagShape::NoFollowUpDateFlag - | NoteTagShape::BluePersonCheckBox - | NoteTagShape::YellowPersonCheckBox - | NoteTagShape::GreenPersonCheckBox - | NoteTagShape::BlueFlagCheckBox - | NoteTagShape::RedFlagCheckBox - | NoteTagShape::GreenFlagCheckBox - ) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/object_reference.rs b/packages/onenote-converter/src/parser/one/property/object_reference.rs deleted file mode 100644 index aa513ce1eee..00000000000 --- a/packages/onenote-converter/src/parser/one/property/object_reference.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::one::property::references::References; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; -use crate::parser::onestore::types::compact_id::CompactId; -use crate::parser::onestore::types::property::PropertyValue; - -/// A generic object reference. -/// -/// This allows for all sorts of object references (e.g. pages referencing their content). -/// It implements parsing these references from the OneStore mapping table. -pub(crate) struct ObjectReference; - -impl ObjectReference { - pub(crate) fn parse(prop_type: PropertyType, object: &Object) -> Result> { - // Validate the value of the property - match object.props().get(prop_type) { - Some(property) => property.to_object_id().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("object reference is not a object id".into()) - })?, - None => return Ok(None), - }; - - // Find the correct object reference - let index = Self::get_offset(prop_type, object)?; - - let id = object - .props() - .object_ids() - .iter() - .nth(index) - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("object id index corrupt".into()))?; - - Ok(Self::resolve_id(index, id, object)) - } - - pub(crate) fn parse_vec( - prop_type: PropertyType, - object: &Object, - ) -> Result>> { - // Determine the number of object references - let count = match object.props().get(prop_type) { - Some(prop) => prop.to_object_ids().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData( - "object reference array is not a object id array".into(), - ) - })?, - None => return Ok(None), - }; - - // Determine offset for the property for which we want to look up the object reference - let offset = Self::get_offset(prop_type, object)?; - - let references = object.props().object_ids(); - - // Look up the object references by offset/count and resolve them - let object_ids = references - .iter() - .skip(offset) - .take(count as usize) - .enumerate() - .flat_map(|(index, id)| Self::resolve_id(index + offset, id, object)) - .collect(); - - Ok(Some(object_ids)) - } - - pub(crate) fn get_offset(prop_type: PropertyType, object: &Object) -> Result { - let predecessors = References::get_predecessors(prop_type, object)?; - let offset = Self::count_references(predecessors); - - Ok(offset) - } - - pub(crate) fn count_references<'a>(props: impl Iterator) -> usize { - props - .map(|v| match v { - PropertyValue::ObjectId => 1, - PropertyValue::ObjectIds(c) => *c as usize, - PropertyValue::PropertyValues(_, sets) => sets - .iter() - .map(|set| Self::count_references(set.values())) - .sum(), - _ => 0, - }) - .sum() - } - - fn resolve_id(index: usize, id: &CompactId, object: &Object) -> Option { - object.mapping().get_object(index, *id) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/object_space_reference.rs b/packages/onenote-converter/src/parser/one/property/object_space_reference.rs deleted file mode 100644 index 8a8dbfbea45..00000000000 --- a/packages/onenote-converter/src/parser/one/property/object_space_reference.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::cell_id::CellId; -use crate::parser::one::property::references::References; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; -use crate::parser::onestore::types::compact_id::CompactId; -use crate::parser::onestore::types::property::PropertyValue; - -/// A generic object space reference. -/// -/// This allows for all sorts of object space references (e.g. sections referencing their pages). -/// It implements parsing these references from the OneStore mapping table. -pub(crate) struct ObjectSpaceReference; - -impl ObjectSpaceReference { - pub(crate) fn parse_vec( - prop_type: PropertyType, - object: &Object, - ) -> Result>> { - // Determine the number of object space references - let count = match object.props().get(prop_type) { - Some(prop) => prop.to_object_space_ids().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData( - "object space reference array is not a object id array".into(), - ) - })?, - None => return Ok(None), - }; - - // Determine offset for the property for which we want to look up the object space - // reference - let offset = Self::get_offset(prop_type, object)?; - - let references = object.props().object_space_ids(); - - // Look up the object space references by offset/count and resolve them - let object_space_ids = references - .iter() - .skip(offset) - .take(count as usize) - .enumerate() - .flat_map(|(index, id)| Self::resolve_id(index, id, object)) - .collect(); - - Ok(Some(object_space_ids)) - } - - pub(crate) fn get_offset(prop_type: PropertyType, object: &Object) -> Result { - let predecessors = References::get_predecessors(prop_type, object)?; - let offset = Self::count_references(predecessors); - - Ok(offset) - } - - pub(crate) fn count_references<'a>(props: impl Iterator) -> usize { - props - .map(|v| match v { - PropertyValue::ObjectSpaceId => 1, - PropertyValue::ObjectSpaceIds(c) => *c as usize, - PropertyValue::PropertyValues(_, sets) => sets - .iter() - .map(|set| Self::count_references(set.values())) - .sum(), - _ => 0, - }) - .sum() - } - - fn resolve_id(index: usize, id: &CompactId, object: &Object) -> Result { - object - .mapping() - .get_object_space(index, *id) - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("id not defined in mapping".into())) - .map_err(|e| e.into()) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/outline_indent_distance.rs b/packages/onenote-converter/src/parser/one/property/outline_indent_distance.rs deleted file mode 100644 index 349c73e4fbd..00000000000 --- a/packages/onenote-converter/src/parser/one/property/outline_indent_distance.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; -use crate::parser::reader::Reader; - -#[derive(Debug, Clone)] -pub struct OutlineIndentDistance(Vec); - -impl OutlineIndentDistance { - pub fn value(&self) -> &[f32] { - &self.0 - } - - pub(crate) fn into_value(self) -> Vec { - self.0 - } - - pub(crate) fn parse(object: &Object) -> Result> { - let value = match object.props().get(PropertyType::RgOutlineIndentDistance) { - Some(value) => value.to_vec().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("outline indent distance is not a vec".into()) - })?, - None => return Ok(None), - }; - - let mut reader = Reader::new(value); - let count = reader.get_u8()?; - reader.advance(3)?; - - let distances = (0..count) - .map(|_| reader.get_f32()) - .collect::>>()?; - - Ok(Some(OutlineIndentDistance(distances))) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/page_size.rs b/packages/onenote-converter/src/parser/one/property/page_size.rs deleted file mode 100644 index ca1fe9a3f5d..00000000000 --- a/packages/onenote-converter/src/parser/one/property/page_size.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// A page size declaration. -/// -/// See [\[MS-ONE\] 2.3.36]. -/// -/// [\[MS-ONE\] 2.3.36]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/8866c05a-602d-4868-95de-2d8b1a0b9d2e -#[derive(Debug)] -pub(crate) enum PageSize { - Auto, - Us, - AnsiLetter, - AnsiTabloid, - UsLegal, - IsoA3, - IsoA4, - IsoA5, - IsoA6, - JisB4, - JisB5, - JisB6, - JapanesePostcard, - IndexCard, - Billfold, - Custom, -} - -impl PageSize { - pub(crate) fn parse(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value.try_to_u8().ok_or_else(|| { - ErrorKind::MalformedOneNoteIncorrectType(format!( - "page size is not a u8 but {:?}", - value - )) - })?, - None => return Ok(None), - }; - - let page_size = match value { - 0 => PageSize::Auto, - 1 => PageSize::Us, - 2 => PageSize::AnsiLetter, - 3 => PageSize::AnsiTabloid, - 4 => PageSize::UsLegal, - 5 => PageSize::IsoA3, - 6 => PageSize::IsoA4, - 7 => PageSize::IsoA5, - 8 => PageSize::IsoA6, - 9 => PageSize::JisB4, - 10 => PageSize::JisB5, - 11 => PageSize::JisB6, - 12 => PageSize::JapanesePostcard, - 13 => PageSize::IndexCard, - 14 => PageSize::Billfold, - 15 => PageSize::Custom, - _ => { - return Err(ErrorKind::MalformedOneNoteFileData( - format!("invalid page size: {}", value).into(), - ) - .into()) - } - }; - - Ok(Some(page_size)) - } -} - -impl Default for PageSize { - fn default() -> Self { - PageSize::Auto - } -} diff --git a/packages/onenote-converter/src/parser/one/property/paragraph_alignment.rs b/packages/onenote-converter/src/parser/one/property/paragraph_alignment.rs deleted file mode 100644 index 0f9380bdf76..00000000000 --- a/packages/onenote-converter/src/parser/one/property/paragraph_alignment.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// A paragraph's alignment. -/// -/// See [\[MS-ONE\] 2.3.94]. -/// -/// [\[MS-ONE\] 2.3.94]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/36edb135-5e8e-400f-9394-82853d662d90 -#[allow(missing_docs)] -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum ParagraphAlignment { - Unknown, - Left, - Center, - Right, -} - -impl ParagraphAlignment { - pub(crate) fn parse(object: &Object) -> Result> { - let value = match object.props().get(PropertyType::ParagraphAlignment) { - Some(value) => value.try_to_u8().ok_or_else(|| { - ErrorKind::MalformedOneNoteIncorrectType(format!( - "page size is not a u8 but {:?}", - value - )) - })?, - None => return Ok(None), - }; - - Ok(Some(match value { - 0 => ParagraphAlignment::Left, - 1 => ParagraphAlignment::Center, - 2 => ParagraphAlignment::Right, - _ => ParagraphAlignment::Unknown, - })) - } -} - -impl Default for ParagraphAlignment { - fn default() -> Self { - ParagraphAlignment::Left - } -} diff --git a/packages/onenote-converter/src/parser/one/property/references.rs b/packages/onenote-converter/src/parser/one/property/references.rs deleted file mode 100644 index 007dad686aa..00000000000 --- a/packages/onenote-converter/src/parser/one/property/references.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; -use crate::parser::onestore::types::property::{PropertyId, PropertyValue}; - -pub(crate) struct References; - -impl References { - pub(crate) fn get_predecessors<'a>( - prop_type: PropertyType, - object: &'a Object<'a>, - ) -> Result> { - let prop_index = object - .props() - .properties() - .index(PropertyId::new(prop_type as u32)) - .ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData( - format!("no object offset for property {:?}", prop_type).into(), - ) - })?; - - let predecessors = object - .props() - .properties() - .values_with_index() - .filter(move |(idx, _)| *idx < prop_index) - .map(|(_, value)| value); - - Ok(predecessors) - } -} diff --git a/packages/onenote-converter/src/parser/one/property/simple.rs b/packages/onenote-converter/src/parser/one/property/simple.rs deleted file mode 100644 index 5ad30410877..00000000000 --- a/packages/onenote-converter/src/parser/one/property/simple.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; -use crate::parser::reader::Reader; -use crate::parser::shared::guid::Guid; -use crate::parser::utils::Utf16ToString; -use encoding_rs::mem::decode_latin1; - -pub(crate) fn parse_bool(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value.to_bool().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("bool value is not a bool".into()) - })?, - None => return Ok(None), - }; - - Ok(Some(value)) -} - -pub(crate) fn parse_u8(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value - .to_u8() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("u8 value is not a u8".into()))?, - None => return Ok(None), - }; - - Ok(Some(value)) -} - -pub(crate) fn parse_u16(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value - .to_u16() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("u16 value is not a u16".into()))?, - None => return Ok(None), - }; - - Ok(Some(value)) -} - -pub(crate) fn parse_u32(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value - .to_u32() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("u32 value is not a u32".into()))?, - None => return Ok(None), - }; - - Ok(Some(value)) -} - -// Not used at the moment -// -// pub(crate) fn parse_u64(prop_type: PropertyType, object: &Object) -> Result> { -// object -// .props() -// .get(prop_type) -// .map(|value| { -// value -// .to_u64() -// .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("u64 value is not a u64".into())) -// }) -// .transpose() -// .map_err(|e| e.into()) -// } - -pub(crate) fn parse_f32(prop_type: PropertyType, object: &Object) -> Result> { - let value = match object.props().get(prop_type) { - Some(value) => value.to_u32().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("float value is not a u32".into()) - })?, - None => return Ok(None), - }; - - Ok(Some(f32::from_le_bytes(value.to_le_bytes()))) -} - -pub(crate) fn parse_vec(prop_type: PropertyType, object: &Object) -> Result>> { - let data = match object.props().get(prop_type) { - Some(value) => value - .to_vec() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("vec value is not a vec".into()))?, - None => return Ok(None), - }; - - Ok(Some(data.to_vec())) -} - -pub(crate) fn parse_vec_u16(prop_type: PropertyType, object: &Object) -> Result>> { - let data = match object.props().get(prop_type) { - Some(value) => value.to_vec().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("vec u16 value is not a vec".into()) - })?, - None => return Ok(None), - }; - - let vec = data - .chunks_exact(2) - .map(|v| u16::from_le_bytes([v[0], v[1]])) - .collect(); - - Ok(Some(vec)) -} - -pub(crate) fn parse_vec_u32(prop_type: PropertyType, object: &Object) -> Result>> { - let data = match object.props().get(prop_type) { - Some(value) => value - .to_vec() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("vec value is not a vec".into()))?, - None => return Ok(None), - }; - - let vec = data - .chunks_exact(4) - .map(|v| u32::from_le_bytes([v[0], v[1], v[2], v[3]])) - .collect(); - - Ok(Some(vec)) -} - -pub(crate) fn parse_ascii(prop_type: PropertyType, object: &Object) -> Result> { - let data = match object.props().get(prop_type) { - Some(value) => value.to_vec().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("ascii value is not a vec".into()) - })?, - None => return Ok(None), - }; - - let text = decode_latin1(data).to_string(); - - Ok(Some(text)) -} - -pub(crate) fn parse_string(prop_type: PropertyType, object: &Object) -> Result> { - let data = match object.props().get(prop_type) { - Some(value) => value - .to_vec() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("vec value is not a vec".into()))?, - None => return Ok(None), - }; - - let text = data - .utf16_to_string() - .map_err(|_| ErrorKind::MalformedOneNoteFileData("invalid string".into()))?; - - Ok(Some(text)) -} - -pub(crate) fn parse_guid(prop_type: PropertyType, object: &Object) -> Result> { - let data = match object.props().get(prop_type) { - Some(value) => value - .to_vec() - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("guid value is not a vec".into()))?, - None => return Ok(None), - }; - - Ok(Some(Guid::parse(&mut Reader::new(data))?)) -} diff --git a/packages/onenote-converter/src/parser/one/property/time.rs b/packages/onenote-converter/src/parser/one/property/time.rs deleted file mode 100644 index b0983943c89..00000000000 --- a/packages/onenote-converter/src/parser/one/property/time.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::PropertyType; -use crate::parser::onestore::object::Object; - -/// A 32 bit date/time timestamp. -/// -/// See [\[MS-ONE\] 2.3.1] -/// -/// [\[MS-ONE\] 2.3.1]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/82336580-f956-40ea-94ab-d9ab15048395 -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub struct Time(u32); - -impl Time { - pub(crate) fn parse(prop_type: PropertyType, object: &Object) -> Result> { - let time = object - .props() - .get(prop_type) - .map(|value| { - value.to_u32().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("time value is not a u32".into()) - }) - }) - .transpose()? - .map(Time); - - Ok(time) - } -} - -/// A 64 bit date/time timestamp. -/// -/// See [\[MS-DTYP\] 2.3.3] -/// -/// [\[MS-DTYP\] 2.3.3]: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/2c57429b-fdd4-488f-b5fc-9e4cf020fcdf -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct Timestamp(u64); - -impl Timestamp { - pub(crate) fn parse(prop_type: PropertyType, object: &Object) -> Result> { - let timestamp = object - .props() - .get(prop_type) - .map(|value| { - value.to_u64().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("timestamp value is not a u64".into()) - }) - }) - .transpose()? - .map(Timestamp); - - Ok(timestamp) - } -} diff --git a/packages/onenote-converter/src/parser/one/property_set/embedded_file_container.rs b/packages/onenote-converter/src/parser/one/property_set/embedded_file_container.rs deleted file mode 100644 index f52ab5ccb43..00000000000 --- a/packages/onenote-converter/src/parser/one/property_set/embedded_file_container.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property_set::PropertySetId; -use crate::parser::onestore::object::Object; - -/// An embedded file data container. -/// -/// See [\[MS-ONE\] 2.2.59]. -/// -/// [\[MS-ONE\] 2.2.59]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/e2a23dc5-75a5-407f-b5ff-d3412379fa7b -#[derive(Debug)] -pub(crate) struct Data(pub(crate) Vec); - -impl Data { - pub(crate) fn into_value(self) -> Vec { - self.0 - } -} - -pub(crate) fn parse(object: &Object) -> Result { - if object.id() != PropertySetId::EmbeddedFileContainer.as_jcid() { - return Err(ErrorKind::MalformedOneNoteFileData( - format!("unexpected object type: 0x{:X}", object.id().0).into(), - ) - .into()); - } - - let data = object - .file_data() - .ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("embedded file container has no data".into()) - })? - .to_vec(); - - Ok(Data(data)) -} diff --git a/packages/onenote-converter/src/parser/one/property_set/embedded_file_node.rs b/packages/onenote-converter/src/parser/one/property_set/embedded_file_node.rs deleted file mode 100644 index 9cd4c807805..00000000000 --- a/packages/onenote-converter/src/parser/one/property_set/embedded_file_node.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::one::property::file_type::FileType; -use crate::parser::one::property::layout_alignment::LayoutAlignment; -use crate::parser::one::property::object_reference::ObjectReference; -use crate::parser::one::property::time::Time; -use crate::parser::one::property::{simple, PropertyType}; -use crate::parser::one::property_set::note_tag_container::Data as NoteTagData; -use crate::parser::one::property_set::PropertySetId; -use crate::parser::onestore::object::Object; -use crate::utils::utils::log_warn; - -/// An embedded file. -/// -/// See [\[MS-ONE\] 2.2.32]. -/// -/// [\[MS-ONE\] 2.2.32]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/a665b5ad-ff40-4c0c-9e42-4b707254dc3f -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct Data { - pub(crate) last_modified: Time, - pub(crate) picture_container: Option, - pub(crate) layout_max_width: Option, - pub(crate) layout_max_height: Option, - pub(crate) is_layout_size_set_by_user: bool, - pub(crate) text: Option, - pub(crate) text_language_code: Option, - pub(crate) layout_alignment_in_parent: Option, - pub(crate) layout_alignment_self: Option, - pub(crate) embedded_file_container: ExGuid, - pub(crate) embedded_file_name: String, - pub(crate) source_path: Option, - pub(crate) file_type: FileType, - pub(crate) picture_width: Option, - pub(crate) picture_height: Option, - pub(crate) note_tags: Vec, - pub(crate) offset_from_parent_horiz: Option, - pub(crate) offset_from_parent_vert: Option, - pub(crate) recording_duration: Option, -} - -pub(crate) fn parse(object: &Object) -> Result { - if object.id() != PropertySetId::EmbeddedFileNode.as_jcid() { - return Err(ErrorKind::MalformedOneNoteFileData( - format!("unexpected object type: 0x{:X}", object.id().0).into(), - ) - .into()); - } - - let last_modified = Time::parse(PropertyType::LastModifiedTime, object)?.ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("embedded file has no last modified time".into()) - })?; - let picture_container = ObjectReference::parse(PropertyType::PictureContainer, object)?; - let layout_max_width = simple::parse_f32(PropertyType::LayoutMaxWidth, object)?; - let layout_max_height = simple::parse_f32(PropertyType::LayoutMaxHeight, object)?; - let is_layout_size_set_by_user = - simple::parse_bool(PropertyType::IsLayoutSizeSetByUser, object)?.unwrap_or_default(); - let text = simple::parse_string(PropertyType::RichEditTextUnicode, object)?; - let text_language_code = - simple::parse_u16(PropertyType::RichEditTextLangId, object)?.map(|value| value as u32); - let layout_alignment_in_parent = - LayoutAlignment::parse(PropertyType::LayoutAlignmentInParent, object)?; - let layout_alignment_self = LayoutAlignment::parse(PropertyType::LayoutAlignmentSelf, object)?; - let embedded_file_container = - ObjectReference::parse(PropertyType::EmbeddedFileContainer, object)?.ok_or_else(|| { - log_warn!("embeded file has no file container"); - ErrorKind::MalformedOneNoteFileData("embedded file has no file container".into()) - })?; - - let embedded_file_name = simple::parse_string(PropertyType::EmbeddedFileName, object)? - .ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData("embedded file has no file name".into()) - })?; - let source_path = simple::parse_string(PropertyType::SourceFilepath, object)?; - let file_type = FileType::parse(object)?; - let picture_width = simple::parse_f32(PropertyType::PictureWidth, object)?; - let picture_height = simple::parse_f32(PropertyType::PictureHeight, object)?; - let offset_from_parent_horiz = simple::parse_f32(PropertyType::OffsetFromParentHoriz, object)?; - let offset_from_parent_vert = simple::parse_f32(PropertyType::OffsetFromParentVert, object)?; - // let recording_duration = simple::parse_u32(PropertyType::Duration) // FIXME: Record duration property id not known - - let note_tags = NoteTagData::parse(object)?.unwrap_or_default(); - - let data = Data { - last_modified, - picture_container, - layout_max_width, - layout_max_height, - is_layout_size_set_by_user, - text, - text_language_code, - layout_alignment_in_parent, - layout_alignment_self, - embedded_file_container, - embedded_file_name, - source_path, - file_type, - picture_width, - picture_height, - note_tags, - offset_from_parent_horiz, - offset_from_parent_vert, - recording_duration: None, // FIXME: Parse this - }; - - Ok(data) -} diff --git a/packages/onenote-converter/src/parser/one/property_set/embedded_ink_container.rs b/packages/onenote-converter/src/parser/one/property_set/embedded_ink_container.rs deleted file mode 100644 index 735cad2434b..00000000000 --- a/packages/onenote-converter/src/parser/one/property_set/embedded_ink_container.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::object_reference::ObjectReference; -use crate::parser::one::property::object_space_reference::ObjectSpaceReference; -use crate::parser::one::property::{simple, PropertyType}; -use crate::parser::onestore::object::Object; -use crate::parser::onestore::types::compact_id::CompactId; -use crate::parser::onestore::types::jcid::JcId; -use crate::parser::onestore::types::object_prop_set::ObjectPropSet; -use crate::parser::onestore::types::prop_set::PropertySet; -use crate::parser::onestore::types::property::PropertyId; - -/// An embedded ink handwriting container. -#[derive(Debug)] -pub(crate) struct Data { - pub(crate) space_width: Option, - pub(crate) space_height: Option, - - pub(crate) start_x: Option, - pub(crate) start_y: Option, - pub(crate) height: Option, - pub(crate) width: Option, - pub(crate) offset_horiz: Option, - pub(crate) offset_vert: Option, -} - -impl Data { - pub(crate) fn parse(object: &Object) -> Result>> { - let (prop_id, prop_sets) = match object.props().get(PropertyType::TextRunData) { - Some(value) => value.to_property_values().ok_or_else(|| { - ErrorKind::MalformedOneNoteFileData( - "embedded ink container is not a property values list".into(), - ) - })?, - None => return Ok(None), - }; - - let data = prop_sets - .iter() - .map(|props| { - let object = Self::parse_object(object, prop_id, props)?; - let data = Self::parse_data(object)?; - - Ok(data) - }) - .collect::>>()?; - - Ok(Some(data)) - } - - fn parse_object<'a>( - object: &'a Object, - prop_id: PropertyId, - props: &PropertySet, - ) -> Result> { - Ok(Object { - context_id: object.context_id, - jc_id: JcId(prop_id.value()), - props: ObjectPropSet { - object_ids: Self::get_object_ids(props, object)?, - object_space_ids: Self::get_object_space_ids(props, object)?, - context_ids: vec![], - properties: props.clone(), - }, - file_data: None, - mapping: object.mapping.clone(), - }) - } - - fn parse_data(object: Object) -> Result { - let space_width = simple::parse_f32(PropertyType::EmbeddedInkSpaceWidth, &object)?; - let space_height = simple::parse_f32(PropertyType::EmbeddedInkSpaceHeight, &object)?; - - let start_x = simple::parse_f32(PropertyType::EmbeddedInkStartX, &object)?; - let start_y = simple::parse_f32(PropertyType::EmbeddedInkStartY, &object)?; - let height = simple::parse_f32(PropertyType::EmbeddedInkHeight, &object)?; - let width = simple::parse_f32(PropertyType::EmbeddedInkWidth, &object)?; - let offset_horiz = simple::parse_f32(PropertyType::EmbeddedInkOffsetHoriz, &object)?; - let offset_vert = simple::parse_f32(PropertyType::EmbeddedInkOffsetVert, &object)?; - - let data = Data { - space_width, - space_height, - start_x, - start_y, - height, - width, - offset_horiz, - offset_vert, - }; - - Ok(data) - } - - fn get_object_ids(props: &PropertySet, object: &Object) -> Result> { - Ok(object - .props - .object_ids - .iter() - .skip(ObjectReference::get_offset( - PropertyType::TextRunData, - object, - )?) - .take(ObjectReference::count_references(props.values())) - .copied() - .collect()) - } - - fn get_object_space_ids(props: &PropertySet, object: &Object) -> Result> { - Ok(object - .props - .object_ids - .iter() - .skip(ObjectSpaceReference::get_offset( - PropertyType::TextRunData, - object, - )?) - .take(ObjectSpaceReference::count_references(props.values())) - .copied() - .collect()) - } -} diff --git a/packages/onenote-converter/src/parser/one/property_set/iframe_node.rs b/packages/onenote-converter/src/parser/one/property_set/iframe_node.rs deleted file mode 100644 index cf45edb5563..00000000000 --- a/packages/onenote-converter/src/parser/one/property_set/iframe_node.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::one::property::{simple, PropertyType}; -use crate::parser::one::property_set::PropertySetId; -use crate::parser::onestore::object::Object; - -/// An ink data container. -pub(crate) struct Data { - pub(crate) embed_type: Option, - pub(crate) source_url: String, -} - -pub(crate) fn parse(object: &Object) -> Result { - if object.id() != PropertySetId::IFrameNode.as_jcid() { - return Err(ErrorKind::MalformedOneNoteFileData( - format!("unexpected object type: 0x{:X}", object.id().0).into(), - ) - .into()); - } - - let embed_type = simple::parse_u32(PropertyType::ImageEmbedType, object)?; - let source_url = simple::parse_string(PropertyType::ImageEmbeddedUrl, object)? - .ok_or_else(|| ErrorKind::MalformedOneNoteFileData("iframe has no source URL".into()))?; - - Ok(Data { - embed_type, - source_url, - }) -} diff --git a/packages/onenote-converter/src/parser/one/property_set/image_node.rs b/packages/onenote-converter/src/parser/one/property_set/image_node.rs deleted file mode 100644 index d64ca1bf5ff..00000000000 --- a/packages/onenote-converter/src/parser/one/property_set/image_node.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::one::property::layout_alignment::LayoutAlignment; -use crate::parser::one::property::object_reference::ObjectReference; -use crate::parser::one::property::{simple, PropertyType}; -use crate::parser::one::property_set::note_tag_container::Data as NoteTagData; -use crate::parser::one::property_set::PropertySetId; -use crate::parser::onestore::object::Object; - -/// An embedded image. -/// -/// See [\[MS-ONE\] 2.2.24]. -/// -/// [\[MS-ONE\] 2.2.24]: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-one/b7bb4d1a-2a57-4819-9eb4-5a2ce8cf210f -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) struct Data { - // pub(crate) last_modified: Time, - pub(crate) picture_container: Option, - pub(crate) layout_max_width: Option, - pub(crate) layout_max_height: Option, - pub(crate) is_layout_size_set_by_user: bool, - pub(crate) language_code: Option, - pub(crate) alt_text: Option, - pub(crate) layout_alignment_in_parent: Option, - pub(crate) layout_alignment_self: Option, - pub(crate) image_filename: Option, - pub(crate) displayed_page_number: Option, - pub(crate) text: Option, - pub(crate) text_language_code: Option, - pub(crate) picture_width: Option, - pub(crate) picture_height: Option, - pub(crate) hyperlink_url: Option, - pub(crate) note_tags: Vec, - pub(crate) offset_from_parent_horiz: Option, - pub(crate) offset_from_parent_vert: Option, - pub(crate) is_background: bool, - pub(crate) iframe: Vec, -} - -pub(crate) fn parse(object: &Object) -> Result { - if object.id() != PropertySetId::ImageNode.as_jcid() { - return Err(ErrorKind::MalformedOneNoteFileData( - format!("unexpected object type: 0x{:X}", object.id().0).into(), - ) - .into()); - } - - // TODO: add support for last_modified - // let last_modified = Time::parse(PropertyType::LastModifiedTime, object)?.ok_or_else(|| now )?; - // let last_modified = match Time::parse(PropertyType::LastModifiedTime, object) { - // Ok(time) => Ok(time.unwrap()), - // Ok(None) => Ok(now), - // Err(time_err) => Ok(now), - // }?; - let picture_container = ObjectReference::parse(PropertyType::PictureContainer, object)?; - let layout_max_width = simple::parse_f32(PropertyType::LayoutMaxWidth, object)?; - let layout_max_height = simple::parse_f32(PropertyType::LayoutMaxHeight, object)?; - let is_layout_size_set_by_user = - simple::parse_bool(PropertyType::IsLayoutSizeSetByUser, object)?.unwrap_or_default(); - let language_code = simple::parse_u32(PropertyType::LanguageId, object)?; - let alt_text = simple::parse_string(PropertyType::ImageAltText, object)?; - let layout_alignment_in_parent = - LayoutAlignment::parse(PropertyType::LayoutAlignmentInParent, object)?; - let layout_alignment_self = LayoutAlignment::parse(PropertyType::LayoutAlignmentSelf, object)?; - let image_filename = simple::parse_string(PropertyType::ImageFilename, object)?; - let displayed_page_number = simple::parse_u32(PropertyType::DisplayedPageNumber, object)?; - let text = simple::parse_string(PropertyType::RichEditTextUnicode, object)?; - let text_language_code = - simple::parse_u16(PropertyType::RichEditTextLangId, object)?.map(|value| value as u32); - let picture_width = simple::parse_f32(PropertyType::PictureWidth, object)?; - let picture_height = simple::parse_f32(PropertyType::PictureHeight, object)?; - let hyperlink_url = simple::parse_string(PropertyType::WzHyperlinkUrl, object)?; - let offset_from_parent_horiz = simple::parse_f32(PropertyType::OffsetFromParentHoriz, object)?; - let offset_from_parent_vert = simple::parse_f32(PropertyType::OffsetFromParentVert, object)?; - let is_background = simple::parse_bool(PropertyType::IsBackground, object)?.unwrap_or_default(); - - let note_tags = NoteTagData::parse(object)?.unwrap_or_default(); - - let iframe = - ObjectReference::parse_vec(PropertyType::ContentChildNodes, object)?.unwrap_or_default(); - - let data = Data { - // last_modified, - picture_container, - layout_max_width, - layout_max_height, - is_layout_size_set_by_user, - language_code, - alt_text, - layout_alignment_in_parent, - layout_alignment_self, - image_filename, - displayed_page_number, - text, - text_language_code, - picture_width, - picture_height, - hyperlink_url, - note_tags, - offset_from_parent_horiz, - offset_from_parent_vert, - is_background, - iframe, - }; - - Ok(data) -} diff --git a/packages/onenote-converter/src/parser/one/property_set/ink_container.rs b/packages/onenote-converter/src/parser/one/property_set/ink_container.rs deleted file mode 100644 index e0fb3305777..00000000000 --- a/packages/onenote-converter/src/parser/one/property_set/ink_container.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::parser::errors::{ErrorKind, Result}; -use crate::parser::fsshttpb::data::exguid::ExGuid; -use crate::parser::one::property::object_reference::ObjectReference; -use crate::parser::one::property::time::Time; -use crate::parser::one::property::{simple, PropertyType}; -use crate::parser::one::property_set::PropertySetId; -use crate::parser::onestore::object::Object; - -/// An ink container. -#[allow(dead_code)] -pub(crate) struct Data { - pub(crate) offset_from_parent_horiz: Option, - pub(crate) offset_from_parent_vert: Option, - pub(crate) last_modified: Option