├── .npmignore
├── tests
├── anyfile.txt
├── archives
│ ├── www1.zip
│ └── www2.zip
├── scripts
│ ├── stop-server.sh
│ └── start-server.sh
├── package.json
├── plugin.xml
└── tests.js
├── .gitignore
├── sample
├── img
│ └── logo.png
├── index.html
├── css
│ └── index.css
└── js
│ └── index.js
├── .editorconfig
├── .travis.yml
├── NOTICE
├── src
├── browser
│ └── Sync.js
├── ios
│ ├── minizip
│ │ ├── mztools.h
│ │ ├── crypt.h
│ │ ├── ioapi.h
│ │ ├── ioapi.c
│ │ ├── mztools.c
│ │ ├── zip.h
│ │ └── unzip.h
│ ├── SSZipArchive.h
│ └── ContentSync.h
├── windows
│ ├── ZipWinProj
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── ZipWinProj.csproj
│ │ └── PGZipInflate.cs
│ └── SyncProxy.js
└── wp8
│ └── Unzip.cs
├── .jshintrc
├── .github
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── CONTRIBUTING.md
├── .bithoundrc
├── package.json
├── spec
├── helper
│ └── cordova.js
└── index.spec.js
├── plugin.xml
├── www
└── index.js
├── LICENSE
├── CHANGELOG.md
└── README.md
/.npmignore:
--------------------------------------------------------------------------------
1 | sample/
2 | spec/
3 | tests/
--------------------------------------------------------------------------------
/tests/anyfile.txt:
--------------------------------------------------------------------------------
1 | Test file that is enumerated before the directories.
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Mac
2 | .DS_Store
3 |
4 | # Node
5 | /node_modules/
6 | npm-debug.log
7 |
--------------------------------------------------------------------------------
/sample/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phonegap/phonegap-plugin-contentsync/HEAD/sample/img/logo.png
--------------------------------------------------------------------------------
/tests/archives/www1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phonegap/phonegap-plugin-contentsync/HEAD/tests/archives/www1.zip
--------------------------------------------------------------------------------
/tests/archives/www2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phonegap/phonegap-plugin-contentsync/HEAD/tests/archives/www2.zip
--------------------------------------------------------------------------------
/tests/scripts/stop-server.sh:
--------------------------------------------------------------------------------
1 | ps aux | grep -e "python -m SimpleHTTPServer" | grep -v grep | awk '{print "kill -1 " $2}' | sh
2 |
--------------------------------------------------------------------------------
/tests/scripts/start-server.sh:
--------------------------------------------------------------------------------
1 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
2 | cd $DIR/../archives && python -m "SimpleHTTPServer" 4321 &
3 |
--------------------------------------------------------------------------------
/tests/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phonegap-plugin-contentsync-tests",
3 | "version": "1.0.0",
4 | "description": "Tests for phonegap-plugin-contentsync",
5 | "main": "tests.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "Apache-2.0"
11 | }
12 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style of different editors and IDEs.
2 | # editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | charset = utf-8
8 | end_of_line = lf
9 | indent_size = 4
10 | indent_style = space
11 | insert_final_newline = true
12 | trim_trailing_whitespace = true
13 |
14 | [*.json]
15 | indent_size = 2
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '0.10'
4 | branches:
5 | only:
6 | - master
7 | notifications:
8 | slack:
9 | secure: VcJej2eTOwkU9oh/MHXKw/efUMw+o15Fd8yzc8/vR0QVG6ubYaIPlMK9iPTI9+MgkP+DIHxvsVr84XQvM40RSr9M35N21zEJjG/P/He8slmca6MAM9v7V8XEZX9xlptshb276l8DfeJs3sF8YZNnulkqoTBeuXNii5pGUtwG7m0=
10 | email:
11 | - PhoneGapCI@adobe.com
12 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | PhoneGap GUI
2 | Copyright 2013 Adobe Systems Incorporated
3 |
4 | This software is licensed under the Apache License, Version 2.0 (see
5 | LICENSE file).
6 |
7 | This software uses the following third party libraries that may have
8 | licenses differing from that of the software itself. You can find the
9 | libraries and their respective licenses below.
10 |
11 | PhoneGap is a registered trademark or trademark of Adobe Systems Incorporated.
12 |
--------------------------------------------------------------------------------
/src/browser/Sync.js:
--------------------------------------------------------------------------------
1 | function notSupported() {
2 | console.log('ContentSync is not supported on browser platform');
3 | }
4 |
5 | var ContentSync = function() {};
6 | ContentSync.prototype.on = function() { notSupported(); };
7 | ContentSync.prototype.emit = function() { notSupported(); };
8 | ContentSync.prototype.cancel = function() { notSupported(); };
9 |
10 | function sync() {
11 | notSupported();
12 | return new ContentSync();
13 | }
14 |
15 | module.exports = {
16 | sync: sync,
17 | unzip: notSupported,
18 | download: notSupported,
19 | ContentSync: ContentSync
20 | };
21 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "asi": false,
3 | "boss": false,
4 | "camelcase": true,
5 | "curly": true,
6 | "eqeqeq": true,
7 | "eqnull": false,
8 | "es5": false,
9 | "evil": false,
10 | "expr": false,
11 | "forin": true,
12 | "funcscope": false,
13 | "jasmine": true,
14 | "immed": true,
15 | "indent": 4,
16 | "latedef": true,
17 | "loopfunc": false,
18 | "maxerr": 7,
19 | "newcap": true,
20 | "node": true,
21 | "nonew": true,
22 | "plusplus": false,
23 | "quotmark": "single",
24 | "shadow": false,
25 | "strict": false,
26 | "supernew": false,
27 | "trailing": true,
28 | "undef": true,
29 | "white": true
30 | }
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Expected Behaviour
2 |
3 | ### Actual Behaviour
4 |
5 | ### Reproduce Scenario (including but not limited to)
6 |
7 | #### Steps to Reproduce
8 |
9 | #### Platform and Version (eg. Android 5.0 or iOS 9.2.1)
10 |
11 | #### (Android) What device vendor (e.g. Samsung, HTC, Sony...)
12 |
13 | #### Cordova CLI version and cordova platform version
14 |
15 | cordova --version # e.g. 6.0.0
16 | cordova platform version android # e.g. 4.1.1
17 |
18 | #### Plugin version
19 |
20 | cordova plugin version | grep phonegap-plugin-contentsync # e.g. 1.5.3
21 |
22 | #### Sample Code that illustrates the problem
23 |
24 | #### Logs taken while reproducing problem
25 |
--------------------------------------------------------------------------------
/src/ios/minizip/mztools.h:
--------------------------------------------------------------------------------
1 | /*
2 | Additional tools for Minizip
3 | Code: Xavier Roche '2004
4 | License: Same as ZLIB (www.gzip.org)
5 | */
6 |
7 | #ifndef _zip_tools_H
8 | #define _zip_tools_H
9 |
10 | #ifdef __cplusplus
11 | extern "C" {
12 | #endif
13 |
14 | #ifndef _ZLIB_H
15 | #include "zlib.h"
16 | #endif
17 |
18 | #include "unzip.h"
19 |
20 | /* Repair a ZIP file (missing central directory)
21 | file: file to recover
22 | fileOut: output file after recovery
23 | fileOutTmp: temporary file name used for recovery
24 | */
25 | extern int ZEXPORT unzRepair(const char* file,
26 | const char* fileOut,
27 | const char* fileOutTmp,
28 | uLong* nRecovered,
29 | uLong* bytesRecovered);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/tests/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 | PhoneGap Content Sync Plugin Tests
8 | Apache 2.0
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/windows/ZipWinProj/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Resources;
2 | using System.Reflection;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTitle("ZipWinProj")]
10 | [assembly: AssemblyDescription("")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("")]
13 | [assembly: AssemblyProduct("ZipWinProj")]
14 | [assembly: AssemblyCopyright("Copyright © 2015")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 | [assembly: NeutralResourcesLanguage("en")]
18 |
19 | // Version information for an assembly consists of the following four values:
20 | //
21 | // Major Version
22 | // Minor Version
23 | // Build Number
24 | // Revision
25 | //
26 | // You can specify all the values or you can default the Build and Revision Numbers
27 | // by using the '*' as shown below:
28 | // [assembly: AssemblyVersion("1.0.*")]
29 | [assembly: AssemblyVersion("1.0.0.0")]
30 | [assembly: AssemblyFileVersion("1.0.0.0")]
31 |
--------------------------------------------------------------------------------
/.bithoundrc:
--------------------------------------------------------------------------------
1 | {
2 | "ignore": [
3 | "**/deps/**",
4 | "**/node_modules/**",
5 | "**/thirdparty/**",
6 | "**/third_party/**",
7 | "**/vendor/**",
8 | "**/**-min-**",
9 | "**/**-min.**",
10 | "**/**.min.**",
11 | "**/**jquery.?(ui|effects)-*.*.?(*).?(cs|j)s",
12 | "**/**jquery-*.*.?(*).?(cs|j)s",
13 | "**/prototype?(*).js",
14 | "**/**?(*).ts",
15 | "**/mootools*.*.*.js",
16 | "**/dojo.js",
17 | "**/MochiKit.js",
18 | "**/yahoo-*.js",
19 | "**/yui*.js",
20 | "**/ckeditor*.js",
21 | "**/tiny_mce*.js",
22 | "**/tiny_mce/?(langs|plugins|themes|utils)/**",
23 | "**/MathJax/**",
24 | "**/shBrush*.js",
25 | "**/shCore.js",
26 | "**/shLegacy.js",
27 | "**/modernizr.custom.?(*).js",
28 | "**/knockout-*.*.*.debug.js",
29 | "**/extjs/*.js",
30 | "**/extjs/*.xml",
31 | "**/extjs/*.txt",
32 | "**/extjs/*.html",
33 | "**/extjs/*.properties",
34 | "**/extjs/.sencha",
35 | "**/extjs/docs/**",
36 | "**/extjs/builds/**",
37 | "**/extjs/cmd/**",
38 | "**/extjs/examples/**",
39 | "**/extjs/locale/**",
40 | "**/extjs/packages/**",
41 | "**/extjs/plugins/**",
42 | "**/extjs/resources/**",
43 | "**/extjs/src/**",
44 | "**/extjs/welcome/**",
45 | "bower_components/**"
46 | ],
47 | "test": [
48 | "**/test/**",
49 | "**/tests/**",
50 | "**/spec/**",
51 | "**/specs/**"
52 | ]
53 | }
54 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phonegap-plugin-contentsync",
3 | "description": "Fetch and cache content for your PhoneGap app.",
4 | "version": "1.4.2",
5 | "homepage": "http://github.com/phonegap/phonegap-plugin-contentsync#readme",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/phonegap/phonegap-plugin-contentsync.git"
9 | },
10 | "bugs": {
11 | "url": "https://github.com/phonegap/phonegap-plugin-contentsync/issues"
12 | },
13 | "cordova": {
14 | "id": "phonegap-plugin-contentsync",
15 | "platforms": [
16 | "ios",
17 | "android",
18 | "windows8",
19 | "windows",
20 | "wp8",
21 | "browser",
22 | "osx"
23 | ]
24 | },
25 | "keywords": [
26 | "ecosystem:cordova",
27 | "ecosystem:phonegap",
28 | "cordova-ios",
29 | "cordova-android",
30 | "cordova-windows8",
31 | "cordova-windows",
32 | "cordova-wp8",
33 | "cordova-browser",
34 | "cordova-osx"
35 | ],
36 | "engines": [
37 | {
38 | "name": "cordova",
39 | "version": ">=3.0.0"
40 | }
41 | ],
42 | "author": "Adobe PhoneGap Team",
43 | "license": "Apache-2.0",
44 | "scripts": {
45 | "test": "jasmine-node --color spec",
46 | "paramedic": "./tests/scripts/start-server.sh && cordova-paramedic --platform ios && ./tests/scripts/stop-server.sh"
47 | },
48 | "devDependencies": {
49 | "jasmine-node": "1.14.5",
50 | "pluginpub": "^0.0.9"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Description
4 |
5 |
6 | ## Related Issue
7 |
8 |
9 |
10 |
11 |
12 | ## Motivation and Context
13 |
14 |
15 | ## How Has This Been Tested?
16 |
17 |
18 |
19 |
20 | ## Screenshots (if appropriate):
21 |
22 | ## Types of changes
23 |
24 | - [ ] Bug fix (non-breaking change which fixes an issue)
25 | - [ ] New feature (non-breaking change which adds functionality)
26 | - [ ] Breaking change (fix or feature that would cause existing functionality to change)
27 |
28 | ## Checklist:
29 |
30 |
31 | - [ ] My code follows the code style of this project.
32 | - [ ] My change requires a change to the documentation.
33 | - [ ] I have updated the documentation accordingly.
34 | - [ ] I have read the **CONTRIBUTING** document.
35 | - [ ] I have added tests to cover my changes.
36 | - [ ] All new and existing tests passed.
37 |
--------------------------------------------------------------------------------
/src/ios/SSZipArchive.h:
--------------------------------------------------------------------------------
1 | //
2 | // SSZipArchive.h
3 | // SSZipArchive
4 | //
5 | // Created by Sam Soffes on 7/21/10.
6 | // Copyright (c) Sam Soffes 2010-2014. All rights reserved.
7 | //
8 |
9 | #ifndef _SSZIPARCHIVE_H
10 | #define _SSZIPARCHIVE_H
11 |
12 | #import
13 | #include "unzip.h"
14 |
15 | @protocol SSZipArchiveDelegate;
16 |
17 | @interface SSZipArchive : NSObject
18 |
19 | // Unzip
20 | + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination;
21 | + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error;
22 |
23 | + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id)delegate;
24 | + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id)delegate;
25 |
26 | // Zip
27 | + (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)filenames;
28 | + (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath;
29 |
30 | - (id)initWithPath:(NSString *)path;
31 | - (BOOL)open;
32 | - (BOOL)writeFile:(NSString *)path;
33 | - (BOOL)writeData:(NSData *)data filename:(NSString *)filename;
34 | - (BOOL)close;
35 |
36 | @end
37 |
38 |
39 | @protocol SSZipArchiveDelegate
40 |
41 | @optional
42 |
43 | - (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo;
44 | - (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath;
45 |
46 | - (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
47 | - (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
48 |
49 | - (void)zipArchiveProgressEvent:(NSInteger)loaded total:(NSInteger)total;
50 | @end
51 |
52 | #endif /* _SSZIPARCHIVE_H */
53 |
--------------------------------------------------------------------------------
/sample/index.html:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Hello World
29 |
30 |
31 |
32 |
Apache Cordova
33 |
34 |
Connecting to Device
35 |
Device is Ready
36 |
37 |
38 |
39 |
40 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/ios/ContentSync.h:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 | #import
20 | #import
21 | #import
22 |
23 | enum ProgressState {
24 | Stopped = 0,
25 | Downloading,
26 | Extracting,
27 | Complete
28 | };
29 | typedef NSUInteger ProgressState;
30 |
31 | enum ErrorCodes {
32 | INVALID_URL_ERR = 1,
33 | CONNECTION_ERR,
34 | UNZIP_ERR,
35 | LOCAL_ERR,
36 | #if !TARGET_OS_IOS // this is currently not added to ios. see issue-96
37 | IN_PROGRESS_ERR,
38 | #endif
39 | };
40 | typedef NSUInteger ErrorCodes;
41 |
42 | @interface ContentSyncTask: NSObject
43 |
44 | @property (nonatomic) CDVInvokedUrlCommand* command;
45 | @property (nonatomic) NSURLSessionDownloadTask* downloadTask;
46 | @property (nonatomic) NSString* appId;
47 | @property (nonatomic) NSString* archivePath;
48 | @property (nonatomic) NSInteger progress;
49 | @property (nonatomic) BOOL extractArchive;
50 |
51 | @end
52 |
53 | @interface ContentSync : CDVPlugin
54 |
55 | @property (nonatomic) NSString* currentPath;
56 | @property (nonatomic) NSMutableArray *syncTasks;
57 | @property (nonatomic) NSURLSession* session;
58 | @property (nonatomic) NSMutableArray* trustedHosts;
59 |
60 | - (void) sync:(CDVInvokedUrlCommand*)command;
61 | - (void) cancel:(CDVInvokedUrlCommand*)command;
62 | - (void) download:(CDVInvokedUrlCommand*)command;
63 | - (void) unzip:(CDVInvokedUrlCommand*)command;
64 |
65 | @end
66 |
67 | /**
68 | * NSURLProtocolNoCache
69 | *
70 | * Custom URL Protocol handler to prevent caching of local assets.
71 | */
72 |
73 | @interface NSURLProtocolNoCache : NSURLProtocol
74 | @end
75 |
--------------------------------------------------------------------------------
/spec/helper/cordova.js:
--------------------------------------------------------------------------------
1 | /* global cordova:true */
2 |
3 | /*!
4 | * Module dependencies.
5 | */
6 |
7 | /**
8 | * cordova.js for node.
9 | *
10 | * Think of this as cordova-node, which would be simliar to cordova-android
11 | * or cordova-browser. The purpose of this module is to enable testing
12 | * of a plugin's JavaScript interface.
13 | *
14 | * When this module is first required, it will insert a global cordova
15 | * instance, which can hijack cordova-specific commands within the pluin's
16 | * implementation.
17 | *
18 | * Remember to require this module before the plugin that you want to test.
19 | *
20 | * Example:
21 | *
22 | * var cordova = require('./helper/cordova'),
23 | * myPlugin = require('../www/myPlugin');
24 | */
25 |
26 | module.exports = global.cordova = cordova = {
27 |
28 | /**
29 | * cordova.require Mock.
30 | *
31 | * Hijacks all cordova.requires. By default, it returns an empty function.
32 | * You can define your own implementation of each required module before
33 | * or after it has been required.
34 | *
35 | * See `cordova.required` to learn how to add your own module implemtnation.
36 | */
37 |
38 | require: function(moduleId) {
39 | // define a default function if it doesn't exist
40 | if (!cordova.required[moduleId]) {
41 | cordova.required[moduleId] = function() {};
42 | }
43 | // create a new module mapping between the module Id and cordova.required.
44 | return new ModuleMap(moduleId);
45 | },
46 |
47 | /**
48 | * Cordova module implementations.
49 | *
50 | * A key-value hash, where the key is the module such as 'cordova/exec'
51 | * and the value is the function or object returned.
52 | *
53 | * For example:
54 | *
55 | * var exec = require('cordova/exec');
56 | *
57 | * Will map to:
58 | *
59 | * cordova.required['cordova/exec'];
60 | */
61 |
62 | required: {
63 | // populated at runtime
64 | }
65 | };
66 |
67 | /**
68 | * Module Mapper.
69 | *
70 | * Returns a function that when executed will lookup the implementation
71 | * in cordova.required[id].
72 | *
73 | * @param {String} moduleId is the module name/path, such as 'cordova/exec'
74 | * @return {Function}.
75 | */
76 |
77 | function ModuleMap(moduleId) {
78 | return function() {
79 | // lookup and execute the module's mock implementation, passing
80 | // in any parameters that were provided.
81 | return cordova.required[moduleId].apply(this, arguments);
82 | };
83 | }
84 |
--------------------------------------------------------------------------------
/src/windows/ZipWinProj/ZipWinProj.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | en-US
6 | 12.0
7 | Debug
8 | bin\Debug\
9 | AnyCPU
10 | {6865B02D-95D5-4A75-A130-E08BDBF45A12}
11 | winmdobj
12 | Properties
13 | ZipWinProj
14 | ZipWinProj
15 | en-US
16 | 512
17 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
18 | Profile32
19 | v4.6
20 |
21 |
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
57 |
--------------------------------------------------------------------------------
/src/windows/ZipWinProj/PGZipInflate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.IO.Compression;
5 | using System.Threading.Tasks;
6 | using Windows.Foundation;
7 | using Windows.Storage;
8 | using Windows.Storage.Streams;
9 |
10 | namespace ZipWinProj
11 | {
12 | public sealed class PGZipInflate
13 | {
14 | public static IAsyncAction InflateAsync(StorageFile zipSourceFile, StorageFolder destFolder)
15 | {
16 | return Inflate(zipSourceFile, destFolder).AsAsyncAction();
17 | }
18 |
19 | private static async Task InflateEntryAsync(ZipArchiveEntry entry, StorageFolder destFolder, bool createSub = false)
20 | {
21 |
22 | string filePath = entry.FullName;
23 |
24 | if (!string.IsNullOrEmpty(filePath) && filePath.Contains("/") && !createSub)
25 | {
26 | // Create sub folder
27 | string subFolderName = Path.GetDirectoryName(filePath);
28 |
29 | StorageFolder subFolder;
30 |
31 | // Create or return the sub folder.
32 | subFolder = await destFolder.CreateFolderAsync(subFolderName, CreationCollisionOption.OpenIfExists);
33 |
34 | string newFilePath = Path.GetFileName(filePath);
35 |
36 | if (!string.IsNullOrEmpty(newFilePath))
37 | {
38 | // Unzip file iteratively.
39 | await InflateEntryAsync(entry, subFolder, true);
40 | }
41 | }
42 | else
43 | {
44 | // Read uncompressed contents
45 | using (Stream entryStream = entry.Open())
46 | {
47 | // Create a file to store the contents
48 | StorageFile uncompressedFile = await destFolder.CreateFileAsync(entry.Name, CreationCollisionOption.ReplaceExisting);
49 |
50 | using (IRandomAccessStream uncompressedFileStream =
51 | await uncompressedFile.OpenAsync(FileAccessMode.ReadWrite))
52 | {
53 | using (Stream outstream = uncompressedFileStream.AsStreamForWrite())
54 | {
55 | await entryStream.CopyToAsync(outstream);
56 | outstream.Flush();
57 | }
58 | }
59 | }
60 | }
61 | }
62 |
63 | private static async Task Inflate(StorageFile zipFile, StorageFolder destFolder)
64 | {
65 | if (zipFile == null)
66 | {
67 | throw new Exception("StorageFile (zipFile) passed to Inflate is null");
68 | }
69 | else if (destFolder == null)
70 | {
71 | throw new Exception("StorageFolder (destFolder) passed to Inflate is null");
72 | }
73 |
74 | Stream zipStream = await zipFile.OpenStreamForReadAsync();
75 |
76 | using (ZipArchive zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Read))
77 | {
78 | Debug.WriteLine("Count = " + zipArchive.Entries.Count);
79 | foreach (ZipArchiveEntry entry in zipArchive.Entries)
80 | {
81 | Debug.WriteLine("Extracting {0} to {1}", entry.FullName, destFolder.Path);
82 | try
83 | {
84 | await InflateEntryAsync(entry, destFolder);
85 | }
86 | catch (Exception ex)
87 | {
88 | Debug.WriteLine("Exception: " + ex.Message);
89 | }
90 | }
91 | }
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We love pull requests from everyone.
4 |
5 | [Fork](https://help.github.com/articles/fork-a-repo/), then [clone](https://help.github.com/articles/cloning-a-repository/) the repo:
6 |
7 | ```
8 | git clone git@github.com:your-username/phonegap-plugin-contentsync.git
9 | ```
10 |
11 | Set up a branch for your feature or bugfix with a link to the original repo:
12 |
13 | ```
14 | git checkout -b my-awesome-new-feature
15 | git push --set-upstream origin my-awesome-new-feature
16 | git remote add upstream https://github.com/phonegap/phonegap-plugin-contentsync.git
17 | ```
18 |
19 | Set up the project:
20 |
21 | ```
22 | npm install
23 | ```
24 |
25 | Make sure the tests pass before changing anything:
26 |
27 | ```
28 | npm test
29 | ```
30 |
31 | Make your change. Add tests for your change. Make the tests pass:
32 |
33 | ```
34 | npm test
35 | ```
36 |
37 | Commit changes:
38 |
39 | ```
40 | git commit -m "Cool stuff"
41 | ```
42 |
43 | Consider starting the commit message with an applicable emoji:
44 | * :art: `:art:` when improving the format/structure of the code
45 | * :zap: `:zap:` when improving performance
46 | * :non-potable_water: `:non-potable_water:` when plugging memory leaks
47 | * :memo: `:memo:` when writing docs
48 | * :ambulance: `:ambulance:` a critical hotfix.
49 | * :sparkles: `:sparkles:` when introducing new features
50 | * :bookmark: `:bookmark:` when releasing / version tags
51 | * :rocket: `:rocket:` when deploying stuff
52 | * :penguin: `:penguin:` when fixing something on Android
53 | * :apple: `:apple:` when fixing something on iOS
54 | * :checkered_flag: `:checkered_flag:` when fixing something on Windows
55 | * :bug: `:bug:` when fixing a bug
56 | * :fire: `:fire:` when removing code or files
57 | * :green_heart: `:green_heart:` when fixing the CI build
58 | * :white_check_mark: `:white_check_mark:` when adding tests
59 | * :lock: `:lock:` when dealing with security
60 | * :arrow_up: `:arrow_up:` when upgrading dependencies
61 | * :arrow_down: `:arrow_down:` when downgrading dependencies
62 | * :shirt: `:shirt:` when removing linter warnings
63 | * :hammer: `:hammer:` when doing heavy refactoring
64 | * :heavy_minus_sign: `:heavy_minus_sign:` when removing a dependency.
65 | * :heavy_plus_sign: `:heavy_plus_sign:` when adding a dependency.
66 | * :wrench: `:wrench:` when changing configuration files.
67 | * :globe_with_meridians: `:globe_with_meridians:` when dealing with internationalization and localization.
68 | * :pencil2: `:pencil2:` when fixing typos.
69 | * :hankey: `:hankey:` when writing bad code that needs to be improved.
70 | * :package: `:package:` when updating compiled files or packages.
71 |
72 | Make sure your branch is up to date with the original repo:
73 |
74 | ```
75 | git fetch upstream
76 | git merge upstream/master
77 | ```
78 |
79 | Review your changes and any possible conflicts and push to your fork:
80 |
81 | ```
82 | git push origin
83 | ```
84 |
85 | [Submit a pull request](https://help.github.com/articles/creating-a-pull-request/).
86 |
87 | At this point you're waiting on us. We do our best to keep on top of all the pull requests. We may suggest some changes, improvements or alternatives.
88 |
89 | Some things that will increase the chance that your pull request is accepted:
90 |
91 | - Write tests.
92 | - Write a [good commit message](http://chris.beams.io/posts/git-commit/).
93 | - Make sure the PR merges cleanly with the latest master.
94 | - Describe your feature/bugfix and why it's needed/important in the pull request description.
95 |
96 |
97 | ## Editor Config
98 |
99 | The project uses [.editorconfig](http://editorconfig.org/) to define the coding
100 | style of each file. We recommend that you install the Editor Config extension
101 | for your preferred IDE. Consistency is key.
102 |
103 | ## JSHint
104 |
105 | The project uses [.jshintrc](http://jshint.com/) to define the JavaScript
106 | coding conventions. Most editors now have a JSHint add-on to provide on-save
107 | or on-edit linting.
108 |
--------------------------------------------------------------------------------
/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | content-sync
4 | PhoneGap Content Sync Plugin
5 |
6 | phonegap,content sync
7 | https://github.com/phonegap/phonegap-plugin-contentsync
8 | https://github.com/phonegap/phonegap-plugin-contentsync/issues
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/sample/css/index.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | * {
20 | -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
21 | }
22 |
23 | body {
24 | -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
25 | -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
26 | -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
27 | background-color:#E4E4E4;
28 | background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
29 | background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
30 | background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
31 | background-image:-webkit-gradient(
32 | linear,
33 | left top,
34 | left bottom,
35 | color-stop(0, #A7A7A7),
36 | color-stop(0.51, #E4E4E4)
37 | );
38 | background-attachment:fixed;
39 | font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
40 | font-size:12px;
41 | height:100%;
42 | margin:0px;
43 | padding:0px;
44 | text-transform:uppercase;
45 | width:100%;
46 | }
47 |
48 | /* Portrait layout (default) */
49 | .app {
50 | background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
51 | position:absolute; /* position in the center of the screen */
52 | left:50%;
53 | top:50%;
54 | height:50px; /* text area height */
55 | width:225px; /* text area width */
56 | text-align:center;
57 | padding:180px 0px 0px 0px; /* image height is 200px (bottom 20px are overlapped with text) */
58 | margin:-115px 0px 0px -112px; /* offset vertical: half of image height and text area height */
59 | /* offset horizontal: half of text area width */
60 | }
61 |
62 | /* Landscape layout (with min-width) */
63 | @media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
64 | .app {
65 | background-position:left center;
66 | padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */
67 | margin:-90px 0px 0px -198px; /* offset vertical: half of image height */
68 | /* offset horizontal: half of image width and text area width */
69 | }
70 | }
71 |
72 | h1 {
73 | font-size:24px;
74 | font-weight:normal;
75 | margin:0px;
76 | overflow:visible;
77 | padding:0px;
78 | text-align:center;
79 | }
80 |
81 | .event {
82 | border-radius:4px;
83 | -webkit-border-radius:4px;
84 | color:#FFFFFF;
85 | font-size:12px;
86 | margin:0px 30px;
87 | padding:2px 0px;
88 | }
89 |
90 | .event.listening {
91 | background-color:#333333;
92 | display:block;
93 | }
94 |
95 | .event.received {
96 | background-color:#4B946A;
97 | display:none;
98 | }
99 |
100 | @keyframes fade {
101 | from { opacity: 1.0; }
102 | 50% { opacity: 0.4; }
103 | to { opacity: 1.0; }
104 | }
105 |
106 | @-webkit-keyframes fade {
107 | from { opacity: 1.0; }
108 | 50% { opacity: 0.4; }
109 | to { opacity: 1.0; }
110 | }
111 |
112 | .blink {
113 | animation:fade 3000ms infinite;
114 | -webkit-animation:fade 3000ms infinite;
115 | }
116 |
117 | #progressbar {
118 | background-color: black;
119 | border-radius: 13px; /* (height of inner div) / 2 + padding */
120 | padding: 3px;
121 | }
122 |
123 | #progressbar > div {
124 | background-color:#4B946A;
125 | width: 0%; /* Adjust with JavaScript */
126 | height: 20px;
127 | border-radius: 10px;
128 | }
129 |
--------------------------------------------------------------------------------
/src/ios/minizip/crypt.h:
--------------------------------------------------------------------------------
1 | /* crypt.h -- base code for crypt/uncrypt ZIPfile
2 |
3 |
4 | Version 1.01e, February 12th, 2005
5 |
6 | Copyright (C) 1998-2005 Gilles Vollant
7 |
8 | This code is a modified version of crypting code in Infozip distribution
9 |
10 | The encryption/decryption parts of this source code (as opposed to the
11 | non-echoing password parts) were originally written in Europe. The
12 | whole source package can be freely distributed, including from the USA.
13 | (Prior to January 2000, re-export from the US was a violation of US law.)
14 |
15 | This encryption code is a direct transcription of the algorithm from
16 | Roger Schlafly, described by Phil Katz in the file appnote.txt. This
17 | file (appnote.txt) is distributed with the PKZIP program (even in the
18 | version without encryption capabilities).
19 |
20 | If you don't need crypting in your application, just define symbols
21 | NOCRYPT and NOUNCRYPT.
22 |
23 | This code support the "Traditional PKWARE Encryption".
24 |
25 | The new AES encryption added on Zip format by Winzip (see the page
26 | http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
27 | Encryption is not supported.
28 | */
29 |
30 | #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
31 |
32 | /***********************************************************************
33 | * Return the next byte in the pseudo-random sequence
34 | */
35 | static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
36 | {
37 | unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
38 | * unpredictable manner on 16-bit systems; not a problem
39 | * with any known compiler so far, though */
40 |
41 | temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
42 | return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
43 | }
44 |
45 | /***********************************************************************
46 | * Update the encryption keys with the next byte of plain text
47 | */
48 | static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
49 | {
50 | (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
51 | (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
52 | (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
53 | {
54 | register int keyshift = (int)((*(pkeys+1)) >> 24);
55 | (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
56 | }
57 | return c;
58 | }
59 |
60 |
61 | /***********************************************************************
62 | * Initialize the encryption keys and the random header according to
63 | * the given password.
64 | */
65 | static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
66 | {
67 | *(pkeys+0) = 305419896L;
68 | *(pkeys+1) = 591751049L;
69 | *(pkeys+2) = 878082192L;
70 | while (*passwd != '\0') {
71 | update_keys(pkeys,pcrc_32_tab,(int)*passwd);
72 | passwd++;
73 | }
74 | }
75 |
76 | #define zdecode(pkeys,pcrc_32_tab,c) \
77 | (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
78 |
79 | #define zencode(pkeys,pcrc_32_tab,c,t) \
80 | (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
81 |
82 | #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
83 |
84 | #define RAND_HEAD_LEN 12
85 | /* "last resort" source for second part of crypt seed pattern */
86 | # ifndef ZCR_SEED2
87 | # define ZCR_SEED2 3141592654UL /* use PI as default pattern */
88 | # endif
89 |
90 | static int crypthead(const char* passwd, /* password string */
91 | unsigned char* buf, /* where to write header */
92 | int bufSize,
93 | unsigned long* pkeys,
94 | const unsigned long* pcrc_32_tab,
95 | unsigned long crcForCrypting)
96 | {
97 | int n; /* index in random header */
98 | int t; /* temporary */
99 | int c; /* random byte */
100 | unsigned char header[RAND_HEAD_LEN-2]; /* random header */
101 | static unsigned calls = 0; /* ensure different random header each time */
102 |
103 | if (bufSize> 7) & 0xff;
118 | header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
119 | }
120 | /* Encrypt random header (last two bytes is high word of crc) */
121 | init_keys(passwd, pkeys, pcrc_32_tab);
122 | for (n = 0; n < RAND_HEAD_LEN-2; n++)
123 | {
124 | buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
125 | }
126 | buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
127 | buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
128 | return n;
129 | }
130 |
131 | #endif
132 |
--------------------------------------------------------------------------------
/sample/js/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | var app = {
20 | // Application Constructor
21 | initialize: function() {
22 | this.bindEvents();
23 | },
24 | // Bind Event Listeners
25 | //
26 | // Bind any events that are required on startup. Common events are:
27 | // 'load', 'deviceready', 'offline', and 'online'.
28 | bindEvents: function() {
29 | document.addEventListener('deviceready', this.onDeviceReady, false);
30 | },
31 | // deviceready Event Handler
32 | //
33 | // The scope of 'this' is the event. In order to call the 'receivedEvent'
34 | // function, we must explicitly call 'app.receivedEvent(...);'
35 | onDeviceReady: function() {
36 | app.receivedEvent('deviceready');
37 | },
38 | // Update DOM on a Received Event
39 | receivedEvent: function(id) {
40 | var parentElement = document.getElementById(id);
41 | var listeningElement = parentElement.querySelector('.listening');
42 | var receivedElement = parentElement.querySelector('.received');
43 |
44 | listeningElement.setAttribute('style', 'display:none;');
45 | receivedElement.setAttribute('style', 'display:block;');
46 |
47 | console.log('Received Event: ' + id);
48 |
49 | document.getElementById("syncBtn").onclick = this.sync;
50 | document.getElementById("downloadExtractBtn").onclick = this.download;
51 |
52 | var sync = ContentSync.sync({id: 'myapp', type: 'local'});
53 | sync.on('complete', function(data) {
54 | if(data.localPath) {
55 | var url = "file://"+data.localPath + "/www/index.html";
56 | alert('Sync complete ' + data + ' changing document.location ' + url );
57 | //document.location = url;
58 | ContentSync.loadUrl(url);
59 | }
60 | });
61 | sync.on('error', function(e) {
62 | alert('no synced app. Loading main app');
63 | });
64 | },
65 |
66 | setProgress: function(progress) {
67 | if(progress.status) {
68 | switch(progress.status) {
69 | case 1:
70 | document.getElementById('status').innerHTML = "Downloading...";
71 | break;
72 | case 2:
73 | document.getElementById('status').innerHTML = "Extracting...";
74 | break;
75 | case 3:
76 | document.getElementById('status').innerHTML = "Complete!";
77 | break;
78 | default:
79 | document.getElementById('status').innerHTML = "";
80 | }
81 | }
82 | if(progress.progress) {
83 | var progressBar = document.getElementById('progressbar').children[0];
84 | progressBar.style.width = progress.progress + '%';
85 | }
86 | },
87 |
88 |
89 | sync: function() {
90 | //var url = "https://github.com/timkim/zipTest/archive/master.zip";
91 | var url = "http://localhost:8000/www.zip";
92 | //var sync = ContentSync.sync({ src: url, id: 'myapp', type: 'merge', copyCordovaAssets: true, copyRootApp: false, headers: false, trustHost: true });
93 | //var sync = ContentSync.sync({ src: null, id: 'myapp', type: 'local', copyRootApp: true });
94 | var sync = ContentSync.sync({ src: url, id: 'myapp', type: 'merge', copyCordovaAssets: true });
95 |
96 | var setProgress = this.setProgress;
97 |
98 | sync.on('progress', function(progress) {
99 | console.log("Progress event", progress);
100 | app.setProgress(progress);
101 | });
102 | sync.on('complete', function(data) {
103 | console.log("Complete", data);
104 | //ContentSync.loadUrl("file://"+data.localPath + "/zipTest-master/www/index.html");
105 | //document.location = data.localPath + "/zipTest-master/www/index.html";
106 | });
107 |
108 | sync.on('error', function(e) {
109 | console.log("Something went wrong: ", e);
110 | document.getElementById('status').innerHTML = e;
111 | });
112 | },
113 | download: function() {
114 | document.getElementById("downloadExtractBtn").disabled = true;
115 | var url = "https://github.com/timkim/zipTest/archive/master.zip";
116 | var extract = this.extract;
117 | var setProgress = this.setProgress;
118 | var callback = function(response) {
119 | console.log(response);
120 | if(response.progress) {
121 | app.setProgress(response);
122 |
123 | }
124 | if(response.archiveURL) {
125 | var archiveURL = response.archiveURL;
126 | document.getElementById("downloadExtractBtn").disabled = false;
127 | document.getElementById("downloadExtractBtn").innerHTML = "Extract";
128 | document.getElementById("downloadExtractBtn").onclick = function() {
129 | app.extract(archiveURL);
130 | };
131 | document.getElementById("status").innerHTML = archiveURL;
132 | }
133 | };
134 | ContentSync.download(url, callback);
135 | },
136 | extract: function(archiveURL) {
137 | window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
138 | fs.root.getDirectory('zipOutPut', {create: true}, function(fileEntry) {
139 | var dirUrl = fileEntry.toURL();
140 | var callback = function(response) {
141 | console.log(response);
142 | document.getElementById("downloadExtractBtn").style.display = "none";
143 | document.getElementById("status").innerHTML = "Extracted";
144 | }
145 | console.log(dirUrl, archiveURL);
146 | Zip.unzip(archiveURL, dirUrl, callback);
147 | });
148 | });
149 | }
150 | };
151 |
152 | app.initialize();
153 |
--------------------------------------------------------------------------------
/src/ios/minizip/ioapi.h:
--------------------------------------------------------------------------------
1 | /* ioapi.h -- IO base function header for compress/uncompress .zip
2 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
3 |
4 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
5 |
6 | Modifications for Zip64 support
7 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
8 |
9 | For more info read MiniZip_info.txt
10 |
11 | Changes
12 |
13 | Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
14 | Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
15 | More if/def section may be needed to support other platforms
16 | Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
17 | (but you should use iowin32.c for windows instead)
18 |
19 | */
20 |
21 | #ifndef _ZLIBIOAPI64_H
22 | #define _ZLIBIOAPI64_H
23 |
24 | #if (!defined(_WIN32)) && (!defined(WIN32))
25 |
26 | // Linux needs this to support file operation on files larger then 4+GB
27 | // But might need better if/def to select just the platforms that needs them.
28 |
29 | #ifndef __USE_FILE_OFFSET64
30 | #define __USE_FILE_OFFSET64
31 | #endif
32 | #ifndef __USE_LARGEFILE64
33 | #define __USE_LARGEFILE64
34 | #endif
35 | #ifndef _LARGEFILE64_SOURCE
36 | #define _LARGEFILE64_SOURCE
37 | #endif
38 | #ifndef _FILE_OFFSET_BIT
39 | #define _FILE_OFFSET_BIT 64
40 | #endif
41 | #endif
42 |
43 | #include
44 | #include
45 | #include "zlib.h"
46 |
47 | #define USE_FILE32API
48 | #if defined(USE_FILE32API)
49 | #define fopen64 fopen
50 | #define ftello64 ftell
51 | #define fseeko64 fseek
52 | #else
53 | #ifdef _MSC_VER
54 | #define fopen64 fopen
55 | #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
56 | #define ftello64 _ftelli64
57 | #define fseeko64 _fseeki64
58 | #else // old MSC
59 | #define ftello64 ftell
60 | #define fseeko64 fseek
61 | #endif
62 | #endif
63 | #endif
64 |
65 | /*
66 | #ifndef ZPOS64_T
67 | #ifdef _WIN32
68 | #define ZPOS64_T fpos_t
69 | #else
70 | #include
71 | #define ZPOS64_T uint64_t
72 | #endif
73 | #endif
74 | */
75 |
76 | #ifdef HAVE_MINIZIP64_CONF_H
77 | #include "mz64conf.h"
78 | #endif
79 |
80 | /* a type choosen by DEFINE */
81 | #ifdef HAVE_64BIT_INT_CUSTOM
82 | typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
83 | #else
84 | #ifdef HAS_STDINT_H
85 | #include "stdint.h"
86 | typedef uint64_t ZPOS64_T;
87 | #else
88 |
89 |
90 | #if defined(_MSC_VER) || defined(__BORLANDC__)
91 | typedef unsigned __int64 ZPOS64_T;
92 | #else
93 | typedef unsigned long long int ZPOS64_T;
94 | #endif
95 | #endif
96 | #endif
97 |
98 |
99 |
100 | #ifdef __cplusplus
101 | extern "C" {
102 | #endif
103 |
104 |
105 | #define ZLIB_FILEFUNC_SEEK_CUR (1)
106 | #define ZLIB_FILEFUNC_SEEK_END (2)
107 | #define ZLIB_FILEFUNC_SEEK_SET (0)
108 |
109 | #define ZLIB_FILEFUNC_MODE_READ (1)
110 | #define ZLIB_FILEFUNC_MODE_WRITE (2)
111 | #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
112 |
113 | #define ZLIB_FILEFUNC_MODE_EXISTING (4)
114 | #define ZLIB_FILEFUNC_MODE_CREATE (8)
115 |
116 |
117 | #ifndef ZCALLBACK
118 | #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
119 | #define ZCALLBACK CALLBACK
120 | #else
121 | #define ZCALLBACK
122 | #endif
123 | #endif
124 |
125 |
126 |
127 |
128 | typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
129 | typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
130 | typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
131 | typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
132 | typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
133 |
134 | typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
135 | typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
136 |
137 |
138 | /* here is the "old" 32 bits structure structure */
139 | typedef struct zlib_filefunc_def_s
140 | {
141 | open_file_func zopen_file;
142 | read_file_func zread_file;
143 | write_file_func zwrite_file;
144 | tell_file_func ztell_file;
145 | seek_file_func zseek_file;
146 | close_file_func zclose_file;
147 | testerror_file_func zerror_file;
148 | voidpf opaque;
149 | } zlib_filefunc_def;
150 |
151 | typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
152 | typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
153 | typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode));
154 |
155 | typedef struct zlib_filefunc64_def_s
156 | {
157 | open64_file_func zopen64_file;
158 | read_file_func zread_file;
159 | write_file_func zwrite_file;
160 | tell64_file_func ztell64_file;
161 | seek64_file_func zseek64_file;
162 | close_file_func zclose_file;
163 | testerror_file_func zerror_file;
164 | voidpf opaque;
165 | } zlib_filefunc64_def;
166 |
167 | void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
168 | void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
169 |
170 | /* now internal definition, only for zip.c and unzip.h */
171 | typedef struct zlib_filefunc64_32_def_s
172 | {
173 | zlib_filefunc64_def zfile_func64;
174 | open_file_func zopen32_file;
175 | tell_file_func ztell32_file;
176 | seek_file_func zseek32_file;
177 | } zlib_filefunc64_32_def;
178 |
179 |
180 | #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
181 | #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
182 | //#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
183 | //#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
184 | #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
185 | #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
186 |
187 | voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
188 | long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
189 | ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
190 |
191 | void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
192 |
193 | #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
194 | #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
195 | #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
196 |
197 | #ifdef __cplusplus
198 | }
199 | #endif
200 |
201 | #endif
202 |
--------------------------------------------------------------------------------
/src/ios/minizip/ioapi.c:
--------------------------------------------------------------------------------
1 | /* ioapi.h -- IO base function header for compress/uncompress .zip
2 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
3 |
4 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
5 |
6 | Modifications for Zip64 support
7 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
8 |
9 | For more info read MiniZip_info.txt
10 |
11 | */
12 |
13 | #if (defined(_WIN32))
14 | #define _CRT_SECURE_NO_WARNINGS
15 | #endif
16 |
17 | #include "ioapi.h"
18 |
19 | voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
20 | {
21 | if (pfilefunc->zfile_func64.zopen64_file != NULL)
22 | return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
23 | else
24 | {
25 | return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
26 | }
27 | }
28 |
29 | long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
30 | {
31 | if (pfilefunc->zfile_func64.zseek64_file != NULL)
32 | return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
33 | else
34 | {
35 | uLong offsetTruncated = (uLong)offset;
36 | if (offsetTruncated != offset)
37 | return -1;
38 | else
39 | return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
40 | }
41 | }
42 |
43 | ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
44 | {
45 | if (pfilefunc->zfile_func64.zseek64_file != NULL)
46 | return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
47 | else
48 | {
49 | uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
50 | if ((tell_uLong) == ((uLong)-1))
51 | return (ZPOS64_T)-1;
52 | else
53 | return tell_uLong;
54 | }
55 | }
56 |
57 | void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
58 | {
59 | p_filefunc64_32->zfile_func64.zopen64_file = NULL;
60 | p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
61 | p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
62 | p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
63 | p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
64 | p_filefunc64_32->zfile_func64.ztell64_file = NULL;
65 | p_filefunc64_32->zfile_func64.zseek64_file = NULL;
66 | p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
67 |
68 | #ifndef __clang_analyzer__
69 | p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
70 | #endif
71 |
72 | p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
73 | p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
74 | p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
75 | }
76 |
77 |
78 |
79 | static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
80 | static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
81 | static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
82 | static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
83 | static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
84 | static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
85 | static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
86 |
87 | static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)
88 | {
89 | FILE* file = NULL;
90 | const char* mode_fopen = NULL;
91 | if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
92 | mode_fopen = "rb";
93 | else
94 | if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
95 | mode_fopen = "r+b";
96 | else
97 | if (mode & ZLIB_FILEFUNC_MODE_CREATE)
98 | mode_fopen = "wb";
99 |
100 | if ((filename!=NULL) && (mode_fopen != NULL))
101 | file = fopen(filename, mode_fopen);
102 | return file;
103 | }
104 |
105 | static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)
106 | {
107 | FILE* file = NULL;
108 | const char* mode_fopen = NULL;
109 | if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
110 | mode_fopen = "rb";
111 | else
112 | if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
113 | mode_fopen = "r+b";
114 | else
115 | if (mode & ZLIB_FILEFUNC_MODE_CREATE)
116 | mode_fopen = "wb";
117 |
118 | if ((filename!=NULL) && (mode_fopen != NULL))
119 | file = fopen64((const char*)filename, mode_fopen);
120 | return file;
121 | }
122 |
123 |
124 | static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
125 | {
126 | uLong ret;
127 | ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
128 | return ret;
129 | }
130 |
131 | static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)
132 | {
133 | uLong ret;
134 | ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
135 | return ret;
136 | }
137 |
138 | static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
139 | {
140 | long ret;
141 | ret = ftell((FILE *)stream);
142 | return ret;
143 | }
144 |
145 |
146 | static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
147 | {
148 | ZPOS64_T ret;
149 | ret = ftello64((FILE *)stream);
150 | return ret;
151 | }
152 |
153 | static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin)
154 | {
155 | int fseek_origin=0;
156 | long ret;
157 | switch (origin)
158 | {
159 | case ZLIB_FILEFUNC_SEEK_CUR :
160 | fseek_origin = SEEK_CUR;
161 | break;
162 | case ZLIB_FILEFUNC_SEEK_END :
163 | fseek_origin = SEEK_END;
164 | break;
165 | case ZLIB_FILEFUNC_SEEK_SET :
166 | fseek_origin = SEEK_SET;
167 | break;
168 | default: return -1;
169 | }
170 | ret = 0;
171 | if (fseek((FILE *)stream, offset, fseek_origin) != 0)
172 | ret = -1;
173 | return ret;
174 | }
175 |
176 | static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
177 | {
178 | int fseek_origin=0;
179 | long ret;
180 | switch (origin)
181 | {
182 | case ZLIB_FILEFUNC_SEEK_CUR :
183 | fseek_origin = SEEK_CUR;
184 | break;
185 | case ZLIB_FILEFUNC_SEEK_END :
186 | fseek_origin = SEEK_END;
187 | break;
188 | case ZLIB_FILEFUNC_SEEK_SET :
189 | fseek_origin = SEEK_SET;
190 | break;
191 | default: return -1;
192 | }
193 | ret = 0;
194 |
195 | if(fseeko64((FILE *)stream, (long)offset, fseek_origin) != 0)
196 | ret = -1;
197 |
198 | return ret;
199 | }
200 |
201 |
202 | static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
203 | {
204 | int ret;
205 | ret = fclose((FILE *)stream);
206 | return ret;
207 | }
208 |
209 | static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)
210 | {
211 | int ret;
212 | ret = ferror((FILE *)stream);
213 | return ret;
214 | }
215 |
216 | void fill_fopen_filefunc (pzlib_filefunc_def)
217 | zlib_filefunc_def* pzlib_filefunc_def;
218 | {
219 | pzlib_filefunc_def->zopen_file = fopen_file_func;
220 | pzlib_filefunc_def->zread_file = fread_file_func;
221 | pzlib_filefunc_def->zwrite_file = fwrite_file_func;
222 | pzlib_filefunc_def->ztell_file = ftell_file_func;
223 | pzlib_filefunc_def->zseek_file = fseek_file_func;
224 | pzlib_filefunc_def->zclose_file = fclose_file_func;
225 | pzlib_filefunc_def->zerror_file = ferror_file_func;
226 | pzlib_filefunc_def->opaque = NULL;
227 | }
228 |
229 | void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
230 | {
231 | pzlib_filefunc_def->zopen64_file = fopen64_file_func;
232 | pzlib_filefunc_def->zread_file = fread_file_func;
233 | pzlib_filefunc_def->zwrite_file = fwrite_file_func;
234 | pzlib_filefunc_def->ztell64_file = ftell64_file_func;
235 | pzlib_filefunc_def->zseek64_file = fseek64_file_func;
236 | pzlib_filefunc_def->zclose_file = fclose_file_func;
237 | pzlib_filefunc_def->zerror_file = ferror_file_func;
238 | pzlib_filefunc_def->opaque = NULL;
239 | }
240 |
--------------------------------------------------------------------------------
/www/index.js:
--------------------------------------------------------------------------------
1 | /* global cordova:false */
2 |
3 | /*!
4 | * Module dependencies.
5 | */
6 |
7 | var exec = cordova.require('cordova/exec');
8 |
9 | /**
10 | * ContentSync constructor.
11 | *
12 | * @param {Object} options to initiate a new content synchronization.
13 | * @param {String} src is a URL to the content sync end-point.
14 | * @param {String} id is used as a unique identifier for the sync operation
15 | * @param {Object} type defines the sync strategy applied to the content.
16 | * @param {String} replace completely removes existing content then copies new content.
17 | * @param {String} merge does not modify existing content, but adds new content.
18 | * @param {Object} headers are used to set the headers for when we send a request to the src URL
19 | * @param {Boolean} validateSrc whether to validate src url with a HEAD request before download (ios only, default true).
20 | * @return {ContentSync} instance that can be monitored and cancelled.
21 | */
22 |
23 | var ContentSync = function(options) {
24 | this._handlers = {
25 | 'progress': [],
26 | 'cancel': [],
27 | 'error': [],
28 | 'complete': []
29 | };
30 |
31 | // require options parameter
32 | if (typeof options === 'undefined') {
33 | throw new Error('The options argument is required.');
34 | }
35 |
36 | // require options.src parameter
37 | if (typeof options.src === 'undefined' && options.type !== "local") {
38 | throw new Error('The options.src argument is required for merge replace types.');
39 | }
40 |
41 | // require options.id parameter
42 | if (typeof options.id === 'undefined') {
43 | throw new Error('The options.id argument is required.');
44 | }
45 |
46 | // define synchronization strategy
47 | //
48 | // replace: This is the normal behavior. Existing content is replaced
49 | // completely by the imported content, i.e. is overridden or
50 | // deleted accordingly.
51 | // merge: Existing content is not modified, i.e. only new content is
52 | // added and none is deleted or modified.
53 | // local: Existing content is not modified, i.e. only new content is
54 | // added and none is deleted or modified.
55 | //
56 | if (typeof options.type === 'undefined') {
57 | options.type = 'replace';
58 | }
59 |
60 | if (typeof options.headers === 'undefined') {
61 | options.headers = null;
62 | }
63 |
64 | if (typeof options.copyCordovaAssets === 'undefined') {
65 | options.copyCordovaAssets = false;
66 | }
67 |
68 | if (typeof options.copyRootApp === 'undefined') {
69 | options.copyRootApp = false;
70 | }
71 |
72 | if (typeof options.timeout === 'undefined') {
73 | options.timeout = 15.0;
74 | }
75 |
76 | if (typeof options.trustHost === 'undefined') {
77 | options.trustHost = false;
78 | }
79 |
80 | if (typeof options.manifest === 'undefined') {
81 | options.manifest = "";
82 | }
83 |
84 | if (typeof options.validateSrc === 'undefined') {
85 | options.validateSrc = true;
86 | }
87 |
88 | // store the options to this object instance
89 | this.options = options;
90 |
91 | // triggered on update and completion
92 | var that = this;
93 | var success = function(result) {
94 | if (result && typeof result.progress !== 'undefined') {
95 | that.emit('progress', result);
96 | } else if (result && typeof result.localPath !== 'undefined') {
97 | that.emit('complete', result);
98 | }
99 | };
100 |
101 | // triggered on error
102 | var fail = function(msg) {
103 | var e = (typeof msg === 'string') ? new Error(msg) : msg;
104 | that.emit('error', e);
105 | };
106 |
107 | // wait at least one process tick to allow event subscriptions
108 | setTimeout(function() {
109 | exec(success, fail, 'Sync', 'sync', [options.src, options.id, options.type, options.headers, options.copyCordovaAssets, options.copyRootApp, options.timeout, options.trustHost, options.manifest, options.validateSrc]);
110 | }, 10);
111 | };
112 |
113 | /**
114 | * Cancel the Content Sync
115 | *
116 | * After successfully canceling the content sync process, the `cancel` event
117 | * will be emitted.
118 | */
119 |
120 | ContentSync.prototype.cancel = function() {
121 | var that = this;
122 | var onCancel = function() {
123 | that.emit('cancel');
124 | };
125 | setTimeout(function() {
126 | exec(onCancel, onCancel, 'Sync', 'cancel', [ that.options.id ]);
127 | }, 10);
128 | };
129 |
130 | /**
131 | * Listen for an event.
132 | *
133 | * The following events are supported:
134 | *
135 | * - progress
136 | * - cancel
137 | * - error
138 | * - completion
139 | *
140 | * @param {String} eventName to subscribe to.
141 | * @param {Function} callback triggered on the event.
142 | */
143 |
144 | ContentSync.prototype.on = function(eventName, callback) {
145 | if (this._handlers.hasOwnProperty(eventName)) {
146 | this._handlers[eventName].push(callback);
147 | }
148 | };
149 |
150 | /**
151 | * Emit an event.
152 | *
153 | * This is intended for internal use only.
154 | *
155 | * @param {String} eventName is the event to trigger.
156 | * @param {*} all arguments are passed to the event listeners.
157 | *
158 | * @return {Boolean} is true when the event is triggered otherwise false.
159 | */
160 |
161 | ContentSync.prototype.emit = function() {
162 | var args = Array.prototype.slice.call(arguments);
163 | var eventName = args.shift();
164 |
165 | if (!this._handlers.hasOwnProperty(eventName)) {
166 | return false;
167 | }
168 |
169 | for (var i = 0, length = this._handlers[eventName].length; i < length; i++) {
170 | this._handlers[eventName][i].apply(undefined,args);
171 | }
172 |
173 | return true;
174 | };
175 |
176 | /*!
177 | * Content Sync Plugin.
178 | */
179 |
180 | module.exports = {
181 | /**
182 | * Synchronize the content.
183 | *
184 | * This method will instantiate a new copy of the ContentSync object
185 | * and start synchronizing.
186 | *
187 | * @param {Object} options
188 | * @return {ContentSync} instance
189 | */
190 |
191 | sync: function(options) {
192 | return new ContentSync(options);
193 | },
194 |
195 | /**
196 | * Unzip
197 | *
198 | * This call is to replicate Zip::unzip plugin
199 | *
200 | */
201 |
202 | unzip: function(fileUrl, dirUrl, callback, progressCallback) {
203 | var win = function(result) {
204 | if (result && result.progress) {
205 | if (progressCallback) {
206 | progressCallback(result);
207 | }
208 | } else if (callback) {
209 | callback(0);
210 | }
211 | };
212 | var fail = function(result) {
213 | if (callback) {
214 | callback(-1);
215 | }
216 | };
217 | exec(win, fail, 'Zip', 'unzip', [fileUrl, dirUrl]);
218 | },
219 |
220 | /**
221 | * Download
222 | *
223 | * This call is to replicate nothing but might be used instead of FileTransfer
224 | *
225 | */
226 |
227 | download: function(url, headers, cb) {
228 | var callback = (typeof headers == "function" ? headers : cb);
229 | exec(callback, callback, 'Sync', 'download', [url, null, headers]);
230 | },
231 |
232 | /**
233 | * loadUrl
234 | *
235 | * This method allows loading file:// urls when using WKWebViews on iOS.
236 | *
237 | */
238 |
239 | loadUrl: function(url, cb) {
240 | if(!url) {
241 | throw new Error('URL is required.');
242 | }
243 | exec(cb, cb, 'Sync', 'loadUrl', [url]);
244 | },
245 |
246 |
247 | /**
248 | * ContentSync Object.
249 | *
250 | * Expose the ContentSync object for direct use
251 | * and testing. Typically, you should use the
252 | * .sync helper method.
253 | */
254 |
255 | ContentSync: ContentSync,
256 |
257 | /**
258 | * PROGRESS_STATE enumeration.
259 | *
260 | * Maps to the `progress` event's `status` object.
261 | * The plugin user can customize the enumeration's mapped string
262 | * to a value that's appropriate for their app.
263 | */
264 |
265 | PROGRESS_STATE: {
266 | 0: 'STOPPED',
267 | 1: 'DOWNLOADING',
268 | 2: 'EXTRACTING',
269 | 3: 'COMPLETE'
270 | },
271 |
272 | /**
273 | * ERROR_STATE enumeration.
274 | *
275 | * Maps to the `error` event's `status` object.
276 | * The plugin user can customize the enumeration's mapped string
277 | * to a value that's appropriate for their app.
278 | */
279 |
280 | ERROR_STATE: {
281 | 1: 'INVALID_URL_ERR',
282 | 2: 'CONNECTION_ERR',
283 | 3: 'UNZIP_ERR'
284 | }
285 | };
286 |
--------------------------------------------------------------------------------
/src/ios/minizip/mztools.c:
--------------------------------------------------------------------------------
1 | /*
2 | Additional tools for Minizip
3 | Code: Xavier Roche '2004
4 | License: Same as ZLIB (www.gzip.org)
5 | */
6 |
7 | /* Code */
8 | #include
9 | #include
10 | #include
11 | #include "zlib.h"
12 | #include "unzip.h"
13 | #include "mztools.h"
14 |
15 | #define READ_8(adr) ((unsigned char)*(adr))
16 | #define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) )
17 | #define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) )
18 |
19 | #define WRITE_8(buff, n) do { \
20 | *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \
21 | } while(0)
22 | #define WRITE_16(buff, n) do { \
23 | WRITE_8((unsigned char*)(buff), n); \
24 | WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \
25 | } while(0)
26 | #define WRITE_32(buff, n) do { \
27 | WRITE_16((unsigned char*)(buff), (n) & 0xffff); \
28 | WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \
29 | } while(0)
30 |
31 | extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered)
32 | const char* file;
33 | const char* fileOut;
34 | const char* fileOutTmp;
35 | uLong* nRecovered;
36 | uLong* bytesRecovered;
37 | {
38 | int err = Z_OK;
39 | FILE* fpZip = fopen(file, "rb");
40 | FILE* fpOut = fopen(fileOut, "wb");
41 | FILE* fpOutCD = fopen(fileOutTmp, "wb");
42 | if (fpZip != NULL && fpOut != NULL) {
43 | int entries = 0;
44 | uLong totalBytes = 0;
45 | char header[30];
46 | char filename[256];
47 | char extra[1024];
48 | int offset = 0;
49 | int offsetCD = 0;
50 | while ( fread(header, 1, 30, fpZip) == 30 ) {
51 | int currentOffset = offset;
52 |
53 | /* File entry */
54 | if (READ_32(header) == 0x04034b50) {
55 | unsigned int version = READ_16(header + 4);
56 | unsigned int gpflag = READ_16(header + 6);
57 | unsigned int method = READ_16(header + 8);
58 | unsigned int filetime = READ_16(header + 10);
59 | unsigned int filedate = READ_16(header + 12);
60 | unsigned int crc = READ_32(header + 14); /* crc */
61 | unsigned int cpsize = READ_32(header + 18); /* compressed size */
62 | unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */
63 | unsigned int fnsize = READ_16(header + 26); /* file name length */
64 | unsigned int extsize = READ_16(header + 28); /* extra field length */
65 | filename[0] = extra[0] = '\0';
66 |
67 | /* Header */
68 | if (fwrite(header, 1, 30, fpOut) == 30) {
69 | offset += 30;
70 | } else {
71 | err = Z_ERRNO;
72 | break;
73 | }
74 |
75 | /* Filename */
76 | if (fnsize > 0) {
77 | if (fread(filename, 1, fnsize, fpZip) == fnsize) {
78 | if (fwrite(filename, 1, fnsize, fpOut) == fnsize) {
79 | offset += fnsize;
80 | } else {
81 | err = Z_ERRNO;
82 | break;
83 | }
84 | } else {
85 | err = Z_ERRNO;
86 | break;
87 | }
88 | } else {
89 | err = Z_STREAM_ERROR;
90 | break;
91 | }
92 |
93 | /* Extra field */
94 | if (extsize > 0) {
95 | if (fread(extra, 1, extsize, fpZip) == extsize) {
96 | if (fwrite(extra, 1, extsize, fpOut) == extsize) {
97 | offset += extsize;
98 | } else {
99 | err = Z_ERRNO;
100 | break;
101 | }
102 | } else {
103 | err = Z_ERRNO;
104 | break;
105 | }
106 | }
107 |
108 | /* Data */
109 | {
110 | int dataSize = cpsize;
111 | if (dataSize == 0) {
112 | dataSize = uncpsize;
113 | }
114 | if (dataSize > 0) {
115 | char* data = malloc(dataSize);
116 | if (data != NULL) {
117 | if ((int)fread(data, 1, dataSize, fpZip) == dataSize) {
118 | if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) {
119 | offset += dataSize;
120 | totalBytes += dataSize;
121 | } else {
122 | err = Z_ERRNO;
123 | }
124 | } else {
125 | err = Z_ERRNO;
126 | }
127 | free(data);
128 | if (err != Z_OK) {
129 | break;
130 | }
131 | } else {
132 | err = Z_MEM_ERROR;
133 | break;
134 | }
135 | }
136 | }
137 |
138 | /* Central directory entry */
139 | {
140 | char centralDirectoryEntryHeader[46];
141 | //char* comment = "";
142 | //int comsize = (int) strlen(comment);
143 | WRITE_32(centralDirectoryEntryHeader, 0x02014b50);
144 | WRITE_16(centralDirectoryEntryHeader + 4, version);
145 | WRITE_16(centralDirectoryEntryHeader + 6, version);
146 | WRITE_16(centralDirectoryEntryHeader + 8, gpflag);
147 | WRITE_16(centralDirectoryEntryHeader + 10, method);
148 | WRITE_16(centralDirectoryEntryHeader + 12, filetime);
149 | WRITE_16(centralDirectoryEntryHeader + 14, filedate);
150 | WRITE_32(centralDirectoryEntryHeader + 16, crc);
151 | WRITE_32(centralDirectoryEntryHeader + 20, cpsize);
152 | WRITE_32(centralDirectoryEntryHeader + 24, uncpsize);
153 | WRITE_16(centralDirectoryEntryHeader + 28, fnsize);
154 | WRITE_16(centralDirectoryEntryHeader + 30, extsize);
155 | WRITE_16(centralDirectoryEntryHeader + 32, 0 /*comsize*/);
156 | WRITE_16(centralDirectoryEntryHeader + 34, 0); /* disk # */
157 | WRITE_16(centralDirectoryEntryHeader + 36, 0); /* int attrb */
158 | WRITE_32(centralDirectoryEntryHeader + 38, 0); /* ext attrb */
159 | WRITE_32(centralDirectoryEntryHeader + 42, currentOffset);
160 | /* Header */
161 | if (fwrite(centralDirectoryEntryHeader, 1, 46, fpOutCD) == 46) {
162 | offsetCD += 46;
163 |
164 | /* Filename */
165 | if (fnsize > 0) {
166 | if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) {
167 | offsetCD += fnsize;
168 | } else {
169 | err = Z_ERRNO;
170 | break;
171 | }
172 | } else {
173 | err = Z_STREAM_ERROR;
174 | break;
175 | }
176 |
177 | /* Extra field */
178 | if (extsize > 0) {
179 | if (fwrite(extra, 1, extsize, fpOutCD) == extsize) {
180 | offsetCD += extsize;
181 | } else {
182 | err = Z_ERRNO;
183 | break;
184 | }
185 | }
186 |
187 | /* Comment field */
188 | /*
189 | if (comsize > 0) {
190 | if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) {
191 | offsetCD += comsize;
192 | } else {
193 | err = Z_ERRNO;
194 | break;
195 | }
196 | }
197 | */
198 |
199 | } else {
200 | err = Z_ERRNO;
201 | break;
202 | }
203 | }
204 |
205 | /* Success */
206 | entries++;
207 |
208 | } else {
209 | break;
210 | }
211 | }
212 |
213 | /* Final central directory */
214 | {
215 | int entriesZip = entries;
216 | char finalCentralDirectoryHeader[22];
217 | //char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools";
218 | //int comsize = (int) strlen(comment);
219 | if (entriesZip > 0xffff) {
220 | entriesZip = 0xffff;
221 | }
222 | WRITE_32(finalCentralDirectoryHeader, 0x06054b50);
223 | WRITE_16(finalCentralDirectoryHeader + 4, 0); /* disk # */
224 | WRITE_16(finalCentralDirectoryHeader + 6, 0); /* disk # */
225 | WRITE_16(finalCentralDirectoryHeader + 8, entriesZip); /* hack */
226 | WRITE_16(finalCentralDirectoryHeader + 10, entriesZip); /* hack */
227 | WRITE_32(finalCentralDirectoryHeader + 12, offsetCD); /* size of CD */
228 | WRITE_32(finalCentralDirectoryHeader + 16, offset); /* offset to CD */
229 | WRITE_16(finalCentralDirectoryHeader + 20, 0 /*comsize*/); /* comment */
230 |
231 | /* Header */
232 | if (fwrite(finalCentralDirectoryHeader, 1, 22, fpOutCD) == 22) {
233 |
234 | /* Comment field */
235 | /*
236 | if (comsize > 0) {
237 | if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) {
238 | err = Z_ERRNO;
239 | }
240 | }
241 | */
242 | } else {
243 | err = Z_ERRNO;
244 | }
245 | }
246 |
247 | /* Final merge (file + central directory) */
248 | fclose(fpOutCD);
249 | if (err == Z_OK) {
250 | fpOutCD = fopen(fileOutTmp, "rb");
251 | if (fpOutCD != NULL) {
252 | int nRead;
253 | char buffer[8192];
254 | while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) {
255 | if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) {
256 | err = Z_ERRNO;
257 | break;
258 | }
259 | }
260 | fclose(fpOutCD);
261 | }
262 | }
263 |
264 | /* Close */
265 | fclose(fpZip);
266 | fclose(fpOut);
267 |
268 | /* Wipe temporary file */
269 | (void)remove(fileOutTmp);
270 |
271 | /* Number of recovered entries */
272 | if (err == Z_OK) {
273 | if (nRecovered != NULL) {
274 | *nRecovered = entries;
275 | }
276 | if (bytesRecovered != NULL) {
277 | *bytesRecovered = totalBytes;
278 | }
279 | }
280 | } else {
281 | err = Z_STREAM_ERROR;
282 | }
283 | return err;
284 | }
285 |
--------------------------------------------------------------------------------
/tests/tests.js:
--------------------------------------------------------------------------------
1 | exports.defineAutoTests = function() {
2 |
3 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
4 |
5 | describe('phonegap-plugin-contentsync', function() {
6 |
7 | it("should exist", function() {
8 | expect(window.ContentSync).toBeDefined();
9 | expect(typeof window.ContentSync.sync == 'function').toBe(true);
10 | expect(typeof window.ContentSync.download == 'function').toBe(true);
11 | expect(typeof window.ContentSync.unzip == 'function').toBe(true);
12 | });
13 |
14 | function syncArchive(url, done) {
15 |
16 | var progressEvent = null;
17 | var sync = ContentSync.sync({ src: url, id: 'myapps/myapp', type: 'replace', copyCordovaAssets: false, headers: false });
18 |
19 |
20 | sync.on('progress', function(progress) {
21 | //console.log("in progress callback " + Object.getOwnPropertyNames(progress));
22 | //console.log("onProgress :: " + progress.progress + " status = " + progress.status);
23 | if(!progressEvent) {
24 | progressEvent = progress;
25 | }
26 | });
27 |
28 | sync.on('complete', function(data) {
29 | //console.log("progress = " + progressEvent);
30 | expect(progressEvent).toBeDefined("Progress should have been received");
31 |
32 | //console.log("progressEvent.status = " + progressEvent.status);
33 | expect(progressEvent.status).toBeDefined("Progress event should have a status prop");
34 |
35 | expect(progressEvent.progress).toBeDefined("Progress event should have a progress prop");
36 | //console.log("progressEvent.progress = " + progressEvent.progress);
37 |
38 | //console.log("data = " + data);
39 | expect(data).toBeDefined("On complete, data is not null");
40 | done();
41 | });
42 |
43 | sync.on('error', function (e) {
44 | expect(progressEvent).toBeDefined("Progress should have been received");
45 | expect(e).toBe(null, "Error callback was called :: " + JSON.stringify(e));
46 | //console.log("got error back :: " + e);
47 | done();
48 | });
49 |
50 | }
51 |
52 | it("can sync archive without www folder at root", function(done){
53 | var url = "http://localhost:4321/www1.zip";
54 | syncArchive(url, done);
55 | }, 60000); // wait a full 60 secs
56 |
57 | it("can sync archive with www folder at root", function(done){
58 | var url = "http://localhost:4321/www2.zip";
59 | syncArchive(url, done);
60 | }, 60000); // wait a full 60 secs
61 |
62 | it('reports error on 404', function(done){
63 | var sync = ContentSync.sync({
64 | src: 'https://www.google.com/error/not/found.zip',
65 | id: 'test' + (new Date().getTime()), // ensure that repeated tests work
66 | type: 'replace',
67 | copyCordovaAssets: false
68 | });
69 | sync.on('complete', function() {
70 | fail('404 page should not complete');
71 | done();
72 | });
73 |
74 | sync.on('error', function(e) {
75 | expect(e).toBeDefined('error should be reported');
76 | done();
77 | });
78 | }, 60000); // wait a full 60 secs for slow Android emulator
79 |
80 | it('tests copyCordovaAssets works without copyRootApp', function(done) {
81 | var appId = 'copyCordovaAssets' + (new Date().getTime());
82 | var sync = ContentSync.sync({
83 | id: appId,
84 | copyCordovaAssets: true,
85 | type: 'local'
86 | });
87 |
88 | sync.on('complete', function(data) {
89 | // cordova.js should be available in the synced directory
90 | testFileExists(appId + '/cordova.js', function success() {
91 | done();
92 | }, function fail() {
93 | fail('cordova.js should exist in the synced directory.');
94 | });
95 | });
96 | });
97 |
98 | /**
99 | * Helper function that tests if the file at the given path exists
100 | */
101 | function testFileExists(path, success, fail) {
102 | var filePath;
103 | if (path.indexOf('file://') === 0) {
104 | // test via system url
105 | filePath = path;
106 | } else {
107 | // test via cordova.file.dataDirectory location
108 | filePath = cordova.file.dataDirectory + '/' + path;
109 | }
110 | window.resolveLocalFileSystemURL(filePath, function(fileEntry) {
111 | expect(fileEntry).toBeDefined();
112 | success();
113 | }, function(e){
114 | fail(path + ' should exist in local copy. Error code ' + e.code);
115 | });
116 | }
117 |
118 | /**
119 | * Helper function that syncs and test if the local copy has the `/index.html`
120 | */
121 | function syncAndTest(appId, useLocalPath, success, fail) {
122 | var sync = ContentSync.sync({
123 | id: appId,
124 | type: 'local',
125 | copyRootApp: true
126 | });
127 | sync.on('complete', function (data) {
128 | if (useLocalPath && cordova.platformId !== 'windows') {
129 | testFileExists('file://' + data.localPath + '/index.html', success, fail);
130 | } else {
131 | testFileExists(appId + '/index.html', success, fail);
132 | }
133 | });
134 | sync.on('error', function (e) {
135 | fail();
136 | });
137 | }
138 |
139 | /**
140 | * Tests if the local copy is at the correct place and can be accessed via file plugin.
141 | */
142 | it('local copy is accessible via file plugin', function(done) {
143 | var appId = 'test' + (new Date()).getTime(); // create new id every time
144 | syncAndTest(appId, false, done, function(e){
145 | fail(e);
146 | done();
147 | })
148 | }, 60000); // wait a full 60 secs for slow Android emulator
149 |
150 | it('create local copy with www prefix', function(done) {
151 | var appId = 'www/local/test' + (new Date()).getTime(); // create new id every time
152 | syncAndTest(appId, true, done, function(e){
153 | fail(e);
154 | done();
155 | })
156 | }, 60000); // wait a full 60 secs for slow Android emulator
157 |
158 | it('create local copy with www suffix', function(done) {
159 | var appId = 'local/test' + (new Date()).getTime() + '/www'; // create new id every time
160 | syncAndTest(appId, true, done, function(e){
161 | fail(e);
162 | done();
163 | })
164 | }, 60000); // wait a full 60 secs for slow Android emulator
165 |
166 | /**
167 | * Test for invalid server name
168 | */
169 | it('error on invalid server name', function(done) {
170 | var sync = ContentSync.sync({
171 | src: 'http://servername',
172 | id: 'test' + (new Date().getTime()), // ensure that repeated tests work
173 | type: 'replace',
174 | copyCordovaAssets: false
175 | });
176 | sync.on('complete', function() {
177 | fail('invalid server name should not complete');
178 | done();
179 | });
180 |
181 | sync.on('error', function(e) {
182 | expect(e).toBeDefined('error should be reported');
183 | done();
184 | });
185 | });
186 |
187 | });
188 |
189 |
190 | if(cordova.platformId == 'windows') {
191 | describe('phonegap-plugin-contentsync windows tests', function() {
192 | it("Has linked C# code", function(done){
193 | //
194 | expect(ZipWinProj).toBeDefined("ZipWinProj should exist");
195 | expect(ZipWinProj.PGZipInflate)
196 | .toBeDefined("ZipWinProj.PGZipInflate should exist");
197 | expect(ZipWinProj.PGZipInflate.inflateAsync)
198 | .toBeDefined("ZipWinProj.PGZipInflate.inflateAsync should exist");
199 | done();
200 | });
201 |
202 | });
203 | }
204 |
205 | if (cordova.platformId === 'osx') {
206 | it("syncing the same id concurrently should fail", function(done) {
207 |
208 | var url = "https://github.com/timkim/zipTest/archive/master.zip";
209 | var sync1 = ContentSync.sync({
210 | src: url,
211 | id: 'myapps/myapp',
212 | type: 'replace',
213 | copyCordovaAssets: false,
214 | headers: false
215 | });
216 | var sync2 = ContentSync.sync({
217 | src: url,
218 | id: 'myapps/myapp',
219 | type: 'replace',
220 | copyCordovaAssets: false,
221 | headers: false
222 | });
223 |
224 | var numFinished = 0;
225 |
226 | sync1.on('complete', function(data) {
227 | expect(data).toBeDefined("On complete, data is not null");
228 | if (++numFinished == 2) {
229 | done();
230 | }
231 | });
232 | sync1.on('error', function(e) {
233 | fail(e);
234 | done();
235 | });
236 |
237 | sync2.on('complete', function(data) {
238 | fail('syncing concurrently the same id should fail.');
239 | done();
240 | });
241 | sync2.on('error', function(e) {
242 | expect(e).toEqual(5);
243 | if (++numFinished == 2) {
244 | done();
245 | }
246 | });
247 |
248 | }, 60000); // wait a full 60 secs
249 | }
250 |
251 | };
252 |
253 | exports.defineManualTests = function() {
254 |
255 | };
256 |
--------------------------------------------------------------------------------
/src/windows/SyncProxy.js:
--------------------------------------------------------------------------------
1 | // progress-state
2 | // 0:stopped, 1:downloading,2:extracting,3:complete
3 |
4 | // error-state
5 | // 1:invalid url
6 | // 2:connection err
7 | // 3:unzip err
8 |
9 |
10 | var appData = Windows.Storage.ApplicationData.current;
11 | var FileOpts = Windows.Storage.CreationCollisionOption;
12 | var getFolderFromPathAsync = Windows.Storage.StorageFolder.getFolderFromPathAsync;
13 | var getFileFromPathAsync = Windows.Storage.StorageFile.getFileFromPathAsync;
14 | var replaceExisting = Windows.Storage.NameCollisionOption.replaceExisting;
15 | var AppPath = Windows.ApplicationModel.Package.current.installedLocation.path;
16 |
17 | function cleanPath(pathStr) {
18 | return pathStr.replace(/\//g, "\\");
19 | }
20 |
21 | function copyAndReplaceFileFromPathAsync(path,dest) {
22 | return Windows.Storage.StorageFile.getFileFromPathAsync(path)
23 | .then(function (file) {
24 | return file.copyAsync(dest, file.name, Windows.Storage.NameCollisionOption.replaceExisting);
25 | });
26 | }
27 |
28 | function copyCordovaAssetsAsync(wwwFolder, destWWWFolder) {
29 | return getFolderFromPathAsync(wwwFolder.path + "\\plugins")
30 | .then(function (pluginsFolder) {
31 | return WinJS.Promise.join([recursiveCopyFolderAsync(pluginsFolder, destWWWFolder, null, false),
32 | copyAndReplaceFileFromPathAsync(wwwFolder.path + "\\cordova.js", destWWWFolder),
33 | copyAndReplaceFileFromPathAsync(wwwFolder.path + "\\cordova_plugins.js", destWWWFolder)]);
34 | });
35 | }
36 |
37 | // this can throw exceptions, callers responsibility
38 | function startDownload(src, storageFile) {
39 | var uri = Windows.Foundation.Uri(src);
40 | var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
41 | var download = downloader.createDownload(uri, storageFile);
42 | return download.startAsync();
43 | }
44 |
45 | function recursiveCopyFolderAsync(src, dst, name, skipRoot) {
46 | name = name ? name : src.name;
47 |
48 | var getDestFolder = function () { return WinJS.Promise.wrap(dst); };
49 | if (!skipRoot) {
50 | getDestFolder = function () {
51 | return dst.createFolderAsync(name, FileOpts.openIfExists)
52 | }
53 | }
54 |
55 | return new WinJS.Promise(function (complete, failed) {
56 | WinJS.Promise.join({
57 | destFolder: getDestFolder(),
58 | files: src.getFilesAsync(),
59 | folders: src.getFoldersAsync()
60 | })
61 | .done(function (resultObj) {
62 | //console.log("destFolder = " + resultObj.destFolder.path);
63 | if (!(resultObj.files.length || resultObj.folders.length)) {
64 | // nothing to copy
65 | complete();
66 | return 1;
67 | }
68 | var fileCount = resultObj.files.length;
69 | var copyfolders = function () {
70 | if (!fileCount--) {
71 | complete();
72 | return 2;
73 | }
74 | recursiveCopyFolderAsync(resultObj.folders[fileCount], resultObj.destFolder)
75 | .done(function () {
76 | copyfolders();
77 | }, failed);
78 | };
79 | var copyfiles = function () {
80 | if (!fileCount--) {
81 | // done with files, move on to folders
82 | fileCount = resultObj.folders.length;
83 | copyfolders();
84 | return 3;
85 | }
86 | var file = resultObj.files[fileCount];
87 | //console.log("copying " + file.name + " => " + resultObj.destFolder.name);
88 | file.copyAsync(resultObj.destFolder || dst, file.name, replaceExisting)
89 | .done(function () {
90 | copyfiles();
91 | }, failed);
92 | };
93 | copyfiles();
94 | },
95 | failed);
96 | });
97 | }
98 |
99 |
100 | var Sync = {
101 | sync: function (cbSuccess, cbFail, options) {
102 |
103 | // Note, all defaults are set in base file www/index.js
104 | // so we can proceed knowing these are all defined.
105 | // options = [ src,id,type,headers,bCopyCordovaAssets,bCopyRootApp,timeout] ;
106 |
107 | var src = options[0];
108 | var id = cleanPath(options[1]);
109 | var type = options[2];
110 | var headers = options[3];
111 | var bCopyCordovaAssets = options[4];
112 | var bCopyRootApp = options[5];
113 | var timeout = options[6];
114 | var trustHost = options[7];
115 | var manifest = options[8];
116 |
117 | var destFolderPath = cleanPath(id);
118 | var rootTempFolder = null;
119 |
120 | var destFolder = null;
121 | var destZipFile = null;
122 | var destWWWFolder = null;
123 | var fileName = id;
124 |
125 | if (id.indexOf("\\") > -1) {
126 | var pathParts = id.split("\\");
127 | fileName = pathParts.pop();
128 | }
129 |
130 | if (fileName.indexOf(".zip") < 0) { // todo, could be some.zip/file ...
131 | fileName += ".zip";
132 | }
133 |
134 | var folderExisted = false;
135 | function getOrCreateLocalFolder(folderPath) {
136 | console.log("folderPath = " + folderPath);
137 | return appData.localFolder.getFolderAsync(folderPath)
138 | .then(function (folder) {
139 | folderExisted = true;
140 | return folder;
141 | },
142 | function (err) {
143 | // folder does not exist, let's create it
144 | console.log("error: " + err.description);
145 | return appData.localFolder.createFolderAsync(folderPath)
146 | .then(function (folder) {
147 | return folder;
148 | },
149 | function (err) {
150 |
151 | });
152 | });
153 | }
154 |
155 | WinJS.Promise.join({
156 | wwwFolder: getFolderFromPathAsync(AppPath + "\\www"),
157 | destFolder: getOrCreateLocalFolder(destFolderPath),
158 | destWWWFolder: getOrCreateLocalFolder(destFolderPath + "\\www")
159 | }).done(function (res) {
160 | if (folderExisted && type == 'local') {
161 | // get out of the promise chain
162 | cbSuccess({ 'localPath': destFolderPath, 'status': 3 }, { keepCallback: false });
163 | }
164 | else {
165 | destFolder = res.destFolder;
166 | wwwFolder = res.wwwFolder;
167 | destWWWFolder = res.destWWWFolder;
168 |
169 | var job = WinJS.Promise.wrap(null);
170 | if (bCopyRootApp) {
171 | job = recursiveCopyFolderAsync(wwwFolder, destFolder, "www", true);
172 | }
173 | else {
174 |
175 | }
176 |
177 | job = job.then(function () {
178 | return destFolder.createFileAsync(fileName, FileOpts.replaceExisting).then(function (storageFile) {
179 | destZipFile = storageFile;
180 | },
181 | function (err) {
182 | console.log(err);
183 | });
184 | });
185 | job = job.then(function (res) {
186 | try {
187 | if (src) {
188 | return startDownload(src, destZipFile);
189 | }
190 | else {
191 | return false;
192 | }
193 | } catch (e) {
194 | console.log(e.message);
195 | cbFail(1); // INVALID_URL_ERR
196 | }
197 | }).then(function downloadComplete(dlResult) { // download is done
198 | if (dlResult) {
199 | //console.log("download is complete " + dlResult);
200 | cbSuccess({ 'progress': 50, 'status': 2 }, { keepCallback: true }); // EXTRACTING
201 |
202 | return ZipWinProj.PGZipInflate.inflateAsync(dlResult.resultFile, destFolder)
203 | .then(function (obj) {
204 | //console.log("got a result from inflateAsync :: " + obj);
205 | return true;
206 | },
207 | function (e) {
208 | //console.log("got err from inflateAsync :: " + e);
209 | cbFail(3); // UNZIP_ERR
210 | return false;
211 | });
212 | }
213 | else {
214 | return false;
215 | }
216 |
217 | },
218 | function (err) { // download error
219 | console.log(err);
220 | cbFail(1); // INVALID_URL_ERR
221 | return false;
222 | },
223 | function (progressEvent) {
224 | var total = progressEvent.progress.totalBytesToReceive;
225 | var bytes = progressEvent.progress.bytesReceived;
226 | var progPercent = total ? Math.round(bytes / total * 50) : 0;
227 | cbSuccess({ 'progress': progPercent, 'status': 1 }, { keepCallback: true }); // 0:stopped, 1:downloading, 2:extracting, 3:complete
228 | })
229 | .then(function maybeCopyCordovaAssets(res) {
230 | return bCopyCordovaAssets ? copyCordovaAssetsAsync(wwwFolder, destWWWFolder) : null;
231 | },
232 | function (err) {
233 | console.log("got err : " + err);
234 | })
235 | .then(function (boom) {
236 | cbSuccess({ 'localPath': destFolder, 'status': 3 }, { keepCallback: false });
237 | })
238 |
239 | }
240 | },
241 | function (err) {
242 | console.log("Error: " + err.description);
243 | cbFail(2);
244 | });
245 | },
246 | cancel: function (cbSuccess, cbFail, options) {
247 | var id = options.id;
248 | if (DownloadQueue[id]) {
249 |
250 | var downloadJob = DownloadQueue[id];
251 | if (!downloadJob.isCancelled) { // prevent multiple callbacks for the same cancel
252 | downloadJob.isCancelled = true;
253 | if (!downloadJob.request) {
254 | // todo: abort it
255 | }
256 | DownloadQueue[id] = null;
257 | }
258 | cbSuccess();
259 | }
260 | else {
261 | // TODO: error, id not found
262 | cbFail();
263 | }
264 | },
265 | download: function (cbSuccess, cbFail, options) {
266 | var url = options[0];
267 | var unknown = options[1];
268 | var headers = options[2];
269 | },
270 | unzip: function (cbSuccess, cbFail, options) {
271 | var srcUrl = options[0];
272 | var destUrl = options[1];
273 | }
274 | };
275 |
276 |
277 |
278 | require("cordova/exec/proxy").add("Sync", Sync);
279 | require("cordova/exec/proxy").add("Zip", Sync);
280 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2013 Adobe Systems Incorporated.
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [v1.4.2](https://github.com/phonegap/phonegap-plugin-contentsync/tree/v1.4.1) (2017-12-19)
4 |
5 | [Full Changelog](https://github.com/phonegap/phonegap-plugin-contentsync/compare/v1.4.1...v1.4.2)
6 |
7 | * 🔧✅ Add package.json to tests plugin so cordova-paramedic runs [view commit](https://github.com/phonegap/phonegap-plugin-contentsync/commit/d90c39dd07ff030588afa6b51fd912efb92ec41a)
8 | * #188 - [iOS] calling sync() with options.copyCordovaAssets set does not perform copy [view commit](https://github.com/phonegap/phonegap-plugin-contentsync/commit/41961afb96fafa0c2f954ff39c7884bae5f89416)
9 |
10 | ## [v1.4.1](https://github.com/phonegap/phonegap-plugin-contentsync/tree/v1.4.1) (2017-11-10)
11 |
12 | [Full Changelog](https://github.com/phonegap/phonegap-plugin-contentsync/compare/v1.4.0...v1.4.1)
13 |
14 | * #186 - [iOS] copyRootApp runs a second time on the second launch of the application, overwriting updates [view commit](https://github.com/phonegap/phonegap-plugin-contentsync/commit/931f34a6e68f291b12dfd527ca9a5b83a158e0fb)
15 |
16 | ## [v1.4.0](https://github.com/phonegap/phonegap-plugin-contentsync/tree/v1.4.0) (2016-07-09)
17 |
18 | [Full Changelog](https://github.com/phonegap/phonegap-plugin-contentsync/compare/v1.3.6...v1.4.0)
19 |
20 | * 1.4.0 [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/b991d1de4a5e0eb5fc18a72125b07b93aec1b142)
21 | * :bookmark: Bumping plugin version to 1.4.0 [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/21ee2f5018c9e226bd69e92a9ae5445f9fad0e1c)
22 | * :wrench: Add package-lock.json [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/a52a0c28a5897ba4f7535c680c9abed24467d8f3)
23 | * :penguin: Issue #185: Google Play Blocker: Unsafe implementation of TrustManager [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/dbafa4c63a83a7c0e6d25e97d552fc4bb3570ba7)
24 | * :wrench: Add github template files [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/867685a40db875216e758233cd9ff8a114351344)
25 | * Fix headline (#178) [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/be31081490c0536514be889724fd0a2bd710bbb5)
26 | * Merge branch 'Cognifide-master' [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/61dcc78d454408471fea04e29e806def5dedfa3e)
27 | * Merge branch 'master' of https://github.com/Cognifide/phonegap-plugin-contentsync into Cognifide-master [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/6ad41d32a89b07e33dd508896e6385b7bce3cd2c)
28 | * Issue #166 new copyRootApp behavior: merge [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/7c8e95b23d3e7d0f2ad17db2831e1a9d3e298bdf)
29 | * Merge pull request #1 from Cognifide/initial-copy-and-download-in-background [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/1049407c91d1d937aca72b82b88df3c3e531a39d)
30 | * Starting download only when src is not nil. Initial copy run in background. [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/323aba5233a85d984afb4375bcf5cd6f709ac2f4)
31 | * Updating CHANGELOG [view commit](http://github.com/phonegap/phonegap-plugin-contentsync/commit/5f68b365194f0350ff7367c5d2e5531f69d1cfa9)
32 |
33 | ## [v1.3.6](https://github.com/* remote origin
34 |
35 | Fetch URL: https://github.com//tree/v1.3.6) (2016-07-09)
36 | [Full Changelog](https://github.com/* remote origin
37 | Fetch URL: https://github.com//compare/v1.3.5...v1.3.6)
38 |
39 | * 1.3.6 [view commit](http://github.com/* remote origin
40 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/a1ef7a60ea31976b36686854a045d437eef0fa3f)
41 | * :bookmark: Bumping plugin version to 1.3.6 [view commit](http://github.com/* remote origin
42 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/b1cc6939d68da56a8d8196097be73826461e2f10)
43 | * add OutputPath to ZipWinProj.csproj (#173) [view commit](http://github.com/* remote origin
44 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/7912d9d840b54200f6649c7adc32f4129ceaa826)
45 | * Updating CHANGELOG [view commit](http://github.com/* remote origin
46 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/4d5fea0ac8b39f5b0eea049a31cd7f07bcf106bd)
47 |
48 | ## [v1.3.5](https://github.com/* remote origin
49 |
50 | Fetch URL: https://github.com//tree/v1.3.5) (2016-07-09)
51 | [Full Changelog](https://github.com/* remote origin
52 | Fetch URL: https://github.com//compare/v1.3.4...v1.3.5)
53 |
54 | * 1.3.5 [view commit](http://github.com/* remote origin
55 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/e90680484b04b77fba3d97f28dabccc57f7c6931)
56 | * :bookmark: Bumping plugin version to 1.3.5 [view commit](http://github.com/* remote origin
57 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/1a63fbfdc167033802aca7148c92960e42f9c05b)
58 | * Merge pull request #172 from phonegap/android-fix [view commit](http://github.com/* remote origin
59 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/752ab470c3c267aa87229671ea67dceb7d9f7d0d)
60 | * fixing compile error [view commit](http://github.com/* remote origin
61 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/7273dbd91bff6a4060bc17a391a49edc8262dd88)
62 | * Updating CHANGELOG [view commit](http://github.com/* remote origin
63 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/d388c5af6bc814ae42e1a2bd9ee99acb6a167384)
64 |
65 | ## [v1.3.4](https://github.com/* remote origin
66 |
67 | Fetch URL: https://github.com//tree/v1.3.4) (2016-07-09)
68 | [Full Changelog](https://github.com/* remote origin
69 | Fetch URL: https://github.com//compare/v1.3.3...v1.3.4)
70 |
71 | * 1.3.4 [view commit](http://github.com/* remote origin
72 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/72a7c0b9f843fc0eb61717270a54a7ae2f540d19)
73 | * :bookmark: Bumping plugin version to 1.3.4 [view commit](http://github.com/* remote origin
74 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/19ec8a224eff24efa5ac3e6eb23cf85365d0afa5)
75 | * Merge pull request #171 from ramboz/issue170 [view commit](http://github.com/* remote origin
76 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/c9c070970f76e998b5fa0178cdb49977650a117c)
77 | * :bug: Fixing potential NullPointerException while removing folders on Android [view commit](http://github.com/* remote origin
78 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/713690a27ad908db768a4ee58ef7151d3eeac73d)
79 | * Merge pull request #165 from brevityco/windows-fix [view commit](http://github.com/* remote origin
80 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/d88a36a932977c5503a5e44b6f2cbb235b180ecf)
81 | * Fix unarchiving memory issues [view commit](http://github.com/* remote origin
82 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/e403fab3c06fb8d9772c61fa63bd0bc7f961ec59)
83 | * Updating CHANGELOG [view commit](http://github.com/* remote origin
84 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/372ef32fb00a518c6c9f8f32faa52f09c6d33065)
85 |
86 | ## [v1.3.3](https://github.com/* remote origin
87 |
88 | Fetch URL: https://github.com//tree/v1.3.3) (2016-07-09)
89 | [Full Changelog](https://github.com/* remote origin
90 | Fetch URL: https://github.com//compare/v1.3.2...v1.3.3)
91 |
92 | * 1.3.3 [view commit](http://github.com/* remote origin
93 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/e13bff12f253bdb6346e422ce6cb44e9a62694a4)
94 | * :bookmark: Bumping plugin version to 1.3.3 [view commit](http://github.com/* remote origin
95 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/08f3dd84c2b17427fd7f424244b0b90262aef128)
96 | * Merge pull request #164 from ptit6sky/master [view commit](http://github.com/* remote origin
97 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/3a6cdae00ee1b7a13105a7643b96fb167ef60cfd)
98 | * Add missing semicolons [view commit](http://github.com/* remote origin
99 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/89ab231ecdc20a6221ba7f39b9828421a55def3c)
100 | * :bug::penguin: Issue #162: Replace of data after connection aborted (HTTP code 400 or 500) [view commit](http://github.com/* remote origin
101 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/fbd833923963ef443e7564a218d9d0d162e8e851)
102 | * Updating CHANGELOG [view commit](http://github.com/* remote origin
103 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/692facab73b520edba33ab5db7762d6e44813fef)
104 |
105 | ## [v1.3.2](https://github.com/* remote origin
106 |
107 | Fetch URL: https://github.com//tree/v1.3.2) (2016-07-09)
108 | [Full Changelog](https://github.com/* remote origin
109 | Fetch URL: https://github.com//compare/v1.3.1...v1.3.2)
110 |
111 | * 1.3.2 [view commit](http://github.com/* remote origin
112 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/c2b55c152926d5769a124cfb495ad2d2a2804d0b)
113 | * :bookmark: Bumping plugin version to 1.3.2 [view commit](http://github.com/* remote origin
114 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/6376cfaf4ce4fbf41c07733e7bbac9966ba593e2)
115 | * :bug::apple: Issue #157 - CopyRootApp issue with app store updates [view commit](http://github.com/* remote origin
116 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/0ec7d4b55fa7eb189cf9ca8082be8c8e860ef16f)
117 | * :bug::penguin: Issue #157 - CopyRootApp issue with app store updates [view commit](http://github.com/* remote origin
118 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/4662912dfe52ac7ff3fb17f656c9f665fd5c0a68)
119 | * validateSrc param: to opt out of the HEAD request to validate the url before downloading [view commit](http://github.com/* remote origin
120 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/6378d6aa529d1798bedc170ca1fa99c721c2fbdc)
121 | * Merge pull request #159 from phonegap/issue156 [view commit](http://github.com/* remote origin
122 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/ea83d0a3a813250bf31fc6090f5a3e42616a7712)
123 | * :art::apple: Issue #156: [iOS] - Requesting an resource with the same id does not replace the resource by default [view commit](http://github.com/* remote origin
124 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/5ccc322753eb06a53d6698f3196ea5b650d345eb)
125 | * :sparkles::apple::penguin: Issue #158: Expose HTTP Response codes [view commit](http://github.com/* remote origin
126 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/25882f39a01d26d7b9ac5c93ee63810d81953363)
127 | * :penguin::bug: Fixing NullPointerException possibility [view commit](http://github.com/* remote origin
128 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/103c0103bc090bbdfbcb694f1fb52b53f025f78b)
129 | * Updating CHANGELOG [view commit](http://github.com/* remote origin
130 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/4797cf8478bbfaaa8ff7a92d73a767781a701889)
131 |
132 | ## [v1.3.1](https://github.com/* remote origin
133 |
134 | Fetch URL: https://github.com//tree/v1.3.1) (2016-07-09)
135 | [Full Changelog](https://github.com/* remote origin
136 | Fetch URL: https://github.com//compare/v1.3.0...v1.3.1)
137 |
138 | * 1.3.1 [view commit](http://github.com/* remote origin
139 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/d695ddc6f9139b3b2579b5a808da179ae77a4411)
140 | * :bookmark: Bumping plugin version to 1.3.1 [view commit](http://github.com/* remote origin
141 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/dd91bd0381a7d9e2f414b54803cda07b919f7822)
142 | * :heavy_plus_sign: adding pluginpub dev dependency [view commit](http://github.com/* remote origin
143 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/b246e1366d913610af9c13b6f650053455d2ff26)
144 | * :bug::apple: Issue #156: [iOS] - Requesting an resource with the same id does not replace the resource by default [view commit](http://github.com/* remote origin
145 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/2c3f236a1da2e8ca2aebf609fddf2ee6d9c0078a)
146 | * Issue #155 adding pluginResult for loadUrl [view commit](http://github.com/* remote origin
147 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/47c5d0e717f8d7af8466e9870cf121ec205211d9)
148 | * Merge pull request #154 from rosatof/master [view commit](http://github.com/* remote origin
149 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/670899da72705441f5c250e38ea1d04e891aeb6c)
150 | * fixing sample app [view commit](http://github.com/* remote origin
151 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/b63680e8f0a10a95bff7a25a0b1dbdc03bd07321)
152 | * Merge pull request #153 from rosatof/master [view commit](http://github.com/* remote origin
153 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/6b9d54a90799e219a7730e9025357636a0ae1e47)
154 | * Avoid crash (NullPointerException) on Android if dir.list() return null [view commit](http://github.com/* remote origin
155 | Fetch URL: https://github.com/phonegap/phonegap-plugin-contentsync/commit/303eef0343b06cb40c3e0f973bb90fd58ba78235)
156 |
157 | # Change Log
158 |
--------------------------------------------------------------------------------
/spec/index.spec.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module dependencies.
3 | */
4 |
5 | var cordova = require('./helper/cordova'),
6 | contentSync = require('../www'),
7 | execSpy,
8 | execWin,
9 | options;
10 |
11 | /*!
12 | * Specification.
13 | */
14 |
15 | describe('phonegap-plugin-contentsync', function() {
16 | beforeEach(function() {
17 | options = { src: 'http://path/to/src.zip', id: 'app-1' };
18 | execWin = jasmine.createSpy();
19 | execSpy = spyOn(cordova.required, 'cordova/exec').andCallFake(execWin);
20 | });
21 |
22 | describe('.sync', function() {
23 | it('should require the options parameter', function() {
24 | expect(function() {
25 | options = undefined;
26 | contentSync.sync(options);
27 | }).toThrow();
28 | expect(execSpy).not.toHaveBeenCalled();
29 | });
30 |
31 | it('should require the options.src parameter for merge/replace', function() {
32 | expect(function() {
33 | options.src = undefined;
34 | contentSync.sync(options);
35 | }).toThrow();
36 | expect(execSpy).not.toHaveBeenCalled();
37 | });
38 |
39 | it('should not require the options.src parameter for local', function() {
40 | expect(function() {
41 | options.src = undefined;
42 | options.src = "local";
43 | contentSync.sync(options);
44 | }).not.toThrow();
45 | expect(execSpy).not.toHaveBeenCalled();
46 | });
47 |
48 | it('should require the options.id parameter', function() {
49 | expect(function() {
50 | options.id = undefined;
51 | contentSync.sync(options);
52 | }).toThrow();
53 | expect(execSpy).not.toHaveBeenCalled();
54 | });
55 |
56 | it('should return an instance of ContentSync', function() {
57 | var sync = contentSync.sync(options);
58 | expect(sync).toEqual(jasmine.any(contentSync.ContentSync));
59 | });
60 | });
61 |
62 | describe('.loadUrl', function() {
63 | it('should raise an error if url is not provided', function() {
64 | expect(function() {
65 | contentSync.loadUrl(null);
66 | }).toThrow();
67 | });
68 |
69 | });
70 |
71 | describe('ContentSync instance', function() {
72 | describe('cordova.exec', function() {
73 | it('should call cordova.exec on next process tick', function(done) {
74 | contentSync.sync(options);
75 | setTimeout(function() {
76 | expect(execSpy).toHaveBeenCalledWith(
77 | jasmine.any(Function),
78 | jasmine.any(Function),
79 | 'Sync',
80 | 'sync',
81 | jasmine.any(Object)
82 | );
83 | done();
84 | }, 100);
85 | });
86 |
87 | describe('options.src', function() {
88 | it('should be passed to exec', function(done) {
89 | execSpy.andCallFake(function(win, fail, service, id, args) {
90 | expect(args[0]).toEqual(options.src);
91 | done();
92 | });
93 | contentSync.sync(options);
94 | });
95 | });
96 |
97 | describe('options.id', function() {
98 | it('should be passed to exec', function(done) {
99 | options.id = '1234567890';
100 | execSpy.andCallFake(function(win, fail, service, id, args) {
101 | expect(args[1]).toEqual(options.id);
102 | done();
103 | });
104 | contentSync.sync(options);
105 | });
106 | });
107 |
108 | describe('options.type', function() {
109 | it('should default to "replace"', function(done) {
110 | execSpy.andCallFake(function(win, fail, service, id, args) {
111 | expect(args[2]).toEqual('replace');
112 | done();
113 | });
114 | contentSync.sync(options);
115 | });
116 |
117 | it('should be passed as whatever we specify', function(done) {
118 | options.type = 'superduper';
119 | execSpy.andCallFake(function(win, fail, service, id, args) {
120 | expect(args[2]).toEqual(options.type);
121 | done();
122 | });
123 | contentSync.sync(options);
124 | });
125 | });
126 |
127 | describe('options.headers', function() {
128 | it('should default to null', function(done) {
129 | execSpy.andCallFake(function(win, fail, service, id, args) {
130 | expect(args[3]).toEqual(null);
131 | done();
132 | });
133 | contentSync.sync(options);
134 | });
135 |
136 | it('should be passed as whatever we specify', function(done) {
137 | options.headers = { 'Authorization': 'SECRET_PASSWORD' };
138 | execSpy.andCallFake(function(win, fail, service, id, args) {
139 | expect(args[3]).toEqual(options.headers);
140 | done();
141 | });
142 | contentSync.sync(options);
143 | });
144 | });
145 |
146 | describe('options.copyCordovaAssets', function() {
147 | it('should default to false', function(done) {
148 | execSpy.andCallFake(function(win, fail, service, id, args) {
149 | expect(args[4]).toEqual(false);
150 | done();
151 | });
152 | contentSync.sync(options);
153 | });
154 | it('should be passed as whatever we specify', function(done) {
155 | options.copyCordovaAssets = true;
156 | execSpy.andCallFake(function(win, fail, service, id, args) {
157 | expect(args[4]).toEqual(options.copyCordovaAssets);
158 | done();
159 | });
160 | contentSync.sync(options);
161 | });
162 | });
163 |
164 | describe('options.copyRootApp', function() {
165 | it('should default to false', function(done) {
166 | execSpy.andCallFake(function(win, fail, service, id, args) {
167 | expect(args[5]).toEqual(false);
168 | done();
169 | });
170 | contentSync.sync(options);
171 | });
172 | it('should be passed as whatever we specify', function(done) {
173 | options.copyRootApp = true;
174 | execSpy.andCallFake(function(win, fail, service, id, args) {
175 | expect(args[5]).toEqual(options.copyRootApp);
176 | done();
177 | });
178 | contentSync.sync(options);
179 | });
180 | });
181 | describe('options.timeout', function() {
182 | it('should default to 15.0', function(done) {
183 | execSpy.andCallFake(function(win, fail, service, id, args) {
184 | expect(args[6]).toEqual(15.0);
185 | done();
186 | });
187 | contentSync.sync(options);
188 | });
189 | it('should be passed as whatever we specify', function(done) {
190 | options.timeout = 30.0;
191 | execSpy.andCallFake(function(win, fail, service, id, args) {
192 | expect(args[6]).toEqual(options.timeout);
193 | done();
194 | });
195 | contentSync.sync(options);
196 | });
197 | });
198 | describe('options.trustHost', function() {
199 | it('should default to false', function(done) {
200 | execSpy.andCallFake(function(win, fail, service, id, args) {
201 | expect(args[7]).toEqual(false);
202 | done();
203 | });
204 | contentSync.sync(options);
205 | });
206 | it('should be passed as whatever we specify', function(done) {
207 | options.trustHost = true;
208 | execSpy.andCallFake(function(win, fail, service, id, args) {
209 | expect(args[7]).toEqual(options.trustHost);
210 | done();
211 | });
212 | contentSync.sync(options);
213 | });
214 | });
215 | describe('options.manifest', function() {
216 | it('should default to the empty string', function(done) {
217 | execSpy.andCallFake(function(win, fail, service, id, args) {
218 | expect(args[8]).toEqual("");
219 | done();
220 | });
221 | contentSync.sync(options);
222 | });
223 | it('should be passed as whatever we specify', function(done) {
224 | options.manifest = "manifest.json";
225 | execSpy.andCallFake(function(win, fail, service, id, args) {
226 | expect(args[8]).toEqual(options.manifest);
227 | done();
228 | });
229 | contentSync.sync(options);
230 | });
231 | });
232 | });
233 |
234 | describe('on "progress" event', function() {
235 | it('should be emitted with an argument', function(done) {
236 | execSpy.andCallFake(function(win, fail, service, id, args) {
237 | win({ 'progress': 1 });
238 | });
239 | var sync = contentSync.sync(options);
240 | sync.on('progress', function(data) {
241 | expect(data.progress).toEqual(1);
242 | done();
243 | });
244 | });
245 | });
246 |
247 | describe('on "complete" event', function() {
248 | beforeEach(function() {
249 | execSpy.andCallFake(function(win, fail, service, id, args) {
250 | win({
251 | localPath: 'file:///path/to/content'
252 | });
253 | });
254 | });
255 |
256 | it('should be emitted on success', function(done) {
257 | var sync = contentSync.sync(options);
258 | sync.on('complete', function(data) {
259 | done();
260 | });
261 | });
262 |
263 | it('should provide the data.localPath argument', function(done) {
264 | var sync = contentSync.sync(options);
265 | sync.on('complete', function(data) {
266 | expect(data.localPath).toEqual('file:///path/to/content');
267 | done();
268 | });
269 | });
270 | });
271 |
272 | describe('on "error" event', function() {
273 | it('should be emitted with an Error', function(done) {
274 | execSpy.andCallFake(function(win, fail, service, id, args) {
275 | fail('something went wrong');
276 | });
277 | var sync = contentSync.sync(options);
278 | sync.on('error', function(e) {
279 | expect(e).toEqual(jasmine.any(Error));
280 | expect(e.message).toEqual('something went wrong');
281 | done();
282 | });
283 | });
284 | });
285 |
286 | describe('.cancel()', function() {
287 | it('should delegate to exec', function(done) {
288 | var sync = contentSync.sync(options);
289 | sync.cancel();
290 | setTimeout(function() {
291 | expect(execSpy).toHaveBeenCalled();
292 | expect(execSpy.callCount).toEqual(2); // 1) sync, 2) cancel
293 | expect(execSpy.mostRecentCall.args).toEqual([
294 | jasmine.any(Function),
295 | jasmine.any(Function),
296 | 'Sync',
297 | 'cancel',
298 | [ options.id ]
299 | ]);
300 | done();
301 | }, 100);
302 | });
303 |
304 | it('should emit the "cancel" event', function(done) {
305 | execSpy.andCallFake(function(win, fail, service, id, args) {
306 | win();
307 | });
308 | var sync = contentSync.sync(options);
309 | sync.on('cancel', function() {
310 | done();
311 | });
312 | sync.cancel();
313 | });
314 | });
315 | });
316 |
317 | describe('PROGRESS_STATE enumeration', function() {
318 | it('should defined 0 as STOPPED', function() {
319 | expect(contentSync.PROGRESS_STATE[0]).toEqual('STOPPED');
320 | });
321 |
322 | it('should defined 1 as DOWNLOADING', function() {
323 | expect(contentSync.PROGRESS_STATE[1]).toEqual('DOWNLOADING');
324 | });
325 |
326 | it('should defined 2 as EXTRACTING', function() {
327 | expect(contentSync.PROGRESS_STATE[2]).toEqual('EXTRACTING');
328 | });
329 |
330 | it('should defined 3 as COMPLETE', function() {
331 | expect(contentSync.PROGRESS_STATE[3]).toEqual('COMPLETE');
332 | });
333 | });
334 | });
335 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # phonegap-plugin-contentsync [](https://travis-ci.org/phonegap/phonegap-plugin-contentsync) [![bitHound Score][bithound-img]][bithound-url]
2 |
3 | > Download and cache remotely hosted zipped content bundles, unzipping automatically.
4 |
5 | ## Installation
6 |
7 | This requires phonegap 5.0+ ( current stable v1.2.0 )
8 |
9 | ```
10 | phonegap plugin add phonegap-plugin-contentsync
11 | ```
12 |
13 | It is also possible to install via repo url directly ( unstable )
14 |
15 | ```
16 | phonegap plugin add https://github.com/phonegap/phonegap-plugin-contentsync
17 | ```
18 |
19 | ## Supported Platforms
20 |
21 | - Android
22 | - iOS
23 | - WP8
24 |
25 |
26 | ## Quick Example
27 |
28 | ```javascript
29 | // Create a new instance of ContentSync pointing to zipped resource 'movie-1.zip' - note
30 | // that the url need not end in zip - it just needs to point to something producing
31 | // a application/octet-stream mime type
32 | var sync = ContentSync.sync({
33 | src: 'https://myserver/assets/movie-1.zip',
34 | id: 'movie-1'
35 | });
36 |
37 | sync.on('progress', function(data) {
38 | // data.progress
39 | });
40 |
41 | sync.on('complete', function(data) {
42 | // data.localPath
43 | });
44 |
45 | sync.on('error', function(e) {
46 | // e
47 | });
48 |
49 | sync.on('cancel', function() {
50 | // triggered if event is cancelled
51 | });
52 | ```
53 |
54 | #### Security note:
55 |
56 | For updating a production app using `ContentSync.sync`, **always** use HTTPS. [Other Updaters](https://sparkle-project.github.io/documentation/security/#http-mitm-vulnerability) have had vulnerabilities exposed when updating over insecure HTTP.
57 |
58 | ## API
59 |
60 | ### ContentSync.sync(options)
61 |
62 | Parameter | Description
63 | --------- | ------------
64 | `options.src` | `String` URL to the remotely hosted content. For updates in production, this URL should *always* use HTTPS
65 | `options.id` | `String` Unique identifer to reference the cached content.
66 | `options.type` | `String` _(Optional)_ Defines the copy strategy for the cached content.
The type `replace` is the default behaviour that deletes the old content and caches the new content.
The type `merge` will add the new content to the existing content. This will replace existing files, add new files, but never delete files.
The type `local` returns the full path to the cached content if it exists or downloads it from `options.src` if it doesn't. `options.src` is not required if cached content actually exists.
67 | `options.headers` | `Object` _(Optional)_ Set of headers to use when requesting the remote content from `options.src`.
68 | `options.copyCordovaAssets` | `Boolean` _(Optional)_ Copies `cordova.js`, `cordova_plugins.js` and `plugins/` to sync'd folder. This operation happens after the source content has been cached, so it will override any existing Cordova assets. Default is `false`.
69 | `options.copyRootApp` | `Boolean` _(Optional)_ Copies the `www` folder to sync'd folder. This operation happens before the source content has been cached, then the source content is cached and finally it copies `cordova.js`, `cordova_plugins.js` and `plugins/` to sync'd folder to remain consistent with the installed plugins. Default is `false`.
70 | `options.timeout` | `Double` _(Optional)_ Request timeout. Default is 15 seconds.
71 | `options.trustHost` | `Boolean` _(Optional)_ Trust SSL host. Host defined in `options.src` will be trusted. Ignored if `options.src` is undefined. Not supported on Android.
72 | `options.manifest` | `String` _(Optional)_ If specified the `copyRootApp` functionality will use the list of files contained in the manifest file during it's initial copy. {Android only}
73 | `options.validateSrc` | `Boolean` _(Optional)_ Whether to validate src url with a HEAD request before download (ios only, default true).
74 |
75 | #### Returns
76 |
77 | - Instance of `ContentSync`.
78 |
79 | #### Example
80 |
81 | ```javascript
82 | var sync = ContentSync.sync({
83 | src: 'https://myserver/app/1',
84 | id: 'app-1'
85 | });
86 | ```
87 |
88 | ### sync.on(event, callback)
89 |
90 | Parameter | Description
91 | --------- | ------------
92 | `event` | `String` Name of the event to listen to. See below for all the event names.
93 | `callback` | `Function` is called when the event is triggered.
94 |
95 | ### sync.on('progress', callback)
96 |
97 | The event `progress` will be triggered on each update as the native platform downloads and caches the content.
98 |
99 | Callback Parameter | Description
100 | ------------------ | -----------
101 | `data.progress` | `Integer` Progress percentage between `0 - 100`. The progress includes all actions required to cache the remote content locally. This is different on each platform, but often includes requesting, downloading, and extracting the cached content along with any system cleanup tasks.
102 | `data.status` | `Integer` Enumeration of `PROGRESS_STATE` to describe the current progress state.
103 |
104 | #### Example
105 |
106 | ```javascript
107 | sync.on('progress', function(data) {
108 | // data.progress
109 | // data.status
110 | });
111 | ```
112 |
113 | ### sync.on('complete', callback)
114 |
115 | The event `complete` will be triggered when the content has been successfully cached onto the device.
116 |
117 | Callback Parameter | Description
118 | ------------------ | -----------
119 | `data.localPath` | `String` The file path to the cached content. The file path will be different on each platform and may be relative or absolute. However, it is guaraneteed to be a compatible reference in the browser.
120 | `data.cached` | `Boolean` Set to `true` if options.type is set to `local` and cached content exists. Set to `false` otherwise.
121 |
122 | #### Example
123 |
124 | ```javascript
125 | sync.on('complete', function(data) {
126 | // data.localPath
127 | // data.cached
128 | });
129 | ```
130 |
131 | ### sync.on('error', callback)
132 |
133 | The event `error` will trigger when an internal error occurs and the cache is aborted.
134 |
135 | Callback Parameter | Description
136 | ------------------ | -----------
137 | `e.type` | `Integer` Enumeration of `ERROR_STATE` to describe the current error
138 | `e.responseCode` | `Integer` HTTP error code if available, `-1` otherwise
139 |
140 | #### Example
141 |
142 | ```javascript
143 | sync.on('error', function(e) {
144 | // e
145 | });
146 | ```
147 |
148 | ### sync.on('cancel', callback)
149 |
150 | The event `cancel` will trigger when `sync.cancel` is called.
151 |
152 | Callback Parameter | Description
153 | ------------------ | -----------
154 | `no parameters` |
155 |
156 | #### Example
157 |
158 | ```javascript
159 | sync.on('cancel', function() {
160 | // user cancelled the sync operation
161 | });
162 | ```
163 |
164 | ### sync.cancel()
165 |
166 | Cancels the content sync operation and triggers the cancel callback.
167 |
168 | ```javascript
169 | var sync = ContentSync.sync({
170 | src: 'https://myserver/app/1',
171 | id: 'app-1'
172 | });
173 |
174 | sync.on('cancel', function() {
175 | console.log('content sync was cancelled');
176 | });
177 |
178 | sync.cancel();
179 | ```
180 |
181 | ### ContentSync.PROGRESS_STATE
182 |
183 | An enumeration that describes the current progress state. The mapped `String`
184 | values can be customized for the user's app.
185 |
186 | Integer | Description
187 | ------- | -----------
188 | `0` | `STOPPED`
189 | `1` | `DOWNLOADING`
190 | `2` | `EXTRACTING`
191 | `3` | `COMPLETE`
192 |
193 | ### ContentSync.ERROR_STATE
194 |
195 | An enumeration that describes the received error. The mapped `String`
196 | values can be customized for the user's app.
197 |
198 | Error Code | Description
199 | ------------------ | -----------
200 | `1` | `INVALID_URL_ERR`
201 | `2` | `CONNECTION_ERR`
202 | `3` | `UNZIP_ERR`
203 |
204 | ### ContentSync.unzip || Zip.unzip - ContentSync.download
205 |
206 | If you are using the [Chromium Zip plugin](https://github.com/MobileChromeApps/zip) this plugin won't work for you on iOS. However, it supports the same interface so you don't have to install both.
207 |
208 | ```javascript
209 |
210 | zip.unzip(, , , []);
211 |
212 | ```
213 |
214 | There is also an extra convenience method that can be used to download an archive
215 |
216 | ```javascript
217 |
218 | ContentSync.download(url, headers, cb)
219 |
220 | ```
221 |
222 | The progress events described above also apply for these methods.
223 |
224 | #### Example
225 |
226 | ```javascript
227 | ContentSync.PROGRESS_STATE[1] = 'Downloading the media content...';
228 | ```
229 |
230 | ### ContentSync.loadUrl (cordova-ios > 4.x with cordova-plugin-wkwebview-engine)
231 |
232 | Use this API to load assets after extraction on **cordova-ios > 4.x** and **cordova-plugin-wkwebview-engine**. Do not use `document.location` as it probably won't work. Make sure to prefix your url with `file://`
233 |
234 | ```javascript
235 | var sync = ContentSync.sync({
236 | src: 'https://myserver/app/1',
237 | id: 'app-1'
238 | });
239 |
240 | sync.on('complete', function(data) {
241 | ContentSync.loadUrl('file://' + data.localPath, function() {
242 | console.log('success');
243 | });
244 | });
245 | ```
246 |
247 | ## Working with the Native File System
248 |
249 | One of the main benefits of the content sync plugin is that it does not depend on the File or FileTransfer plugins. As a result the end user should not care where the ContentSync plugin stores it's files as long as it fills the requirements that it is private and removed when it's associated app is uninstalled.
250 |
251 | However, if you do need to use the File plugin to navigate the data downloaded by ContentSync you can use the following code snippet to get a [DirectoryEntry](https://cordova.apache.org/docs/en/3.0.0/cordova_file_file.md.html#DirectoryEntry) for the synced content.
252 |
253 | ```javascript
254 | var sync = ContentSync.sync({
255 | src: 'https://myserver/app/1',
256 | id: 'app-1'
257 | });
258 |
259 | sync.on('complete', function(data) {
260 | window.resolveLocalFileSystemURL("file://" + data.localPath, function(entry) {
261 | // entry is a DirectoryEntry object
262 | }, function(error) {
263 | console.log("Error: " + error.code);
264 | });
265 | });
266 | ```
267 |
268 | As of version 1.2.0 of the plugin the location in which the plugin stores the synched content is equivaltent to the `cordova.file.dataDirectory` path from the `cordova-plugin-file` package. This is a change from previous versions so please be aware you may need to do a full sync after upgrading to version 1.2.0.
269 |
270 | Platform | Path
271 | ------------------ | -----------
272 | Android | `/data/data//files/`
273 | iOS | `/var/mobile/Applications//Library/NoCloud/`
274 |
275 | ## Copy Root App
276 |
277 | The asset file system is pretty slow on Android so in order to speed up the initial copy of your app to the content sync location you can specify a manifest file on Android. The file must be in the format:
278 |
279 | ```javascript
280 | {
281 | 'files': [
282 | 'img/logo.png',
283 | 'index.html',
284 | 'js/index.js'
285 | ]
286 | }
287 | ```
288 |
289 | and if the file is placed in your apps `www` folder you would invoke it via:
290 |
291 | ```javascript
292 | var sync = ContentSync.sync({
293 | src: 'https://myserver/app/1',
294 | id: 'app-1',
295 | copyRootApp: true,
296 | manifest: 'manifest.json'
297 | });
298 | ```
299 |
300 | This results in the `copyRootApp` taking about a third of the time as when a manifest file is not specified.
301 |
302 | ## Persistence of Synced Content
303 |
304 | Content downloaded via this plugin persists between runs of the application or reboots of the phone. The content will only be removed if the application is uninstalled or you use the File API to remove the location of the synched content.
305 |
306 | ## Native Requirements
307 |
308 | - There should be no dependency on the existing File or FileTransfer plugins.
309 | - The native cached file path should be uniquely identifiable with the `id` parameter. This will allow the Content Sync plugin to lookup the file path at a later time using the `id` parameter.
310 | - The first version of the plugin assumes that all cached content is downloaded as a compressed ZIP. The native implementation must properly extract content and clean up any temporary files, such as the downloaded zip.
311 | - The locally compiled Cordova web assets should be copied to the cached content. This includes `cordova.js`, `cordova_plugins.js`, and `plugins/**/*`.
312 | - Multiple syncs should be supported at the same time.
313 |
314 | ## Running Tests ( static tests against source code )
315 |
316 | ```
317 | npm test
318 | ```
319 |
320 | ## Emulator Testing
321 |
322 | The emulator tests use cordova-paramedic and the cordova-plugin-test-framework.
323 | To run them you will need cordova-paramedic installed:
324 |
325 | npm install -g cordova-paramedic
326 |
327 | Some of the tests require a simple HTTP server to host .zip payloads:
328 |
329 | ./tests/scripts/start-server.sh
330 |
331 | Run the tests:
332 |
333 | // From the root of this repo
334 | // test ios :
335 | cordova-paramedic --platform ios --plugin .
336 |
337 | // test android :
338 | cordova-paramedic --platform android --plugin .
339 |
340 | Once complete, the simple HTTP server can be stopped:
341 |
342 | ./tests/scripts/stop-server.sh
343 |
344 | ## Contributing
345 |
346 | ### Editor Config
347 |
348 | The project uses [.editorconfig](http://editorconfig.org/) to define the coding
349 | style of each file. We recommend that you install the Editor Config extension
350 | for your preferred IDE.
351 |
352 | ### JSHint
353 |
354 | The project uses [.jshint](http://jshint.com/docs) to define the JavaScript
355 | coding conventions. Most editors now have a JSHint add-on to provide on-save
356 | or on-edit linting.
357 |
358 | #### Install JSHint for vim
359 |
360 | 1. Install [jshint](https://www.npmjs.com/package/jshint).
361 | 1. Install [jshint.vim](https://github.com/wookiehangover/jshint.vim).
362 |
363 | #### Install JSHint for Sublime
364 |
365 | 1. Install [Package Control](https://packagecontrol.io/installation)
366 | 1. Restart Sublime
367 | 1. Type `CMD+SHIFT+P`
368 | 1. Type _Install Package_
369 | 1. Type _JSHint Gutter_
370 | 1. Sublime -> Preferences -> Package Settings -> JSHint Gutter
371 | 1. Set `lint_on_load` and `lint_on_save` to `true`
372 |
373 | [travis-ci-img]: https://travis-ci.org/phonegap/phonegap-plugin-contentsync.svg?branch=master
374 | [travis-ci-url]: http://travis-ci.org/phonegap/phonegap-plugin-contentsync
375 | [bithound-img]: https://www.bithound.io/github/phonegap/phonegap-plugin-contentsync/badges/score.svg
376 | [bithound-url]: https://www.bithound.io/github/phonegap/phonegap-plugin-contentsync
377 |
--------------------------------------------------------------------------------
/src/ios/minizip/zip.h:
--------------------------------------------------------------------------------
1 | /* zip.h -- IO on .zip files using zlib
2 | Version 1.1, February 14h, 2010
3 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
4 |
5 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
6 |
7 | Modifications for Zip64 support
8 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
9 |
10 | For more info read MiniZip_info.txt
11 |
12 | ---------------------------------------------------------------------------
13 |
14 | Condition of use and distribution are the same than zlib :
15 |
16 | This software is provided 'as-is', without any express or implied
17 | warranty. In no event will the authors be held liable for any damages
18 | arising from the use of this software.
19 |
20 | Permission is granted to anyone to use this software for any purpose,
21 | including commercial applications, and to alter it and redistribute it
22 | freely, subject to the following restrictions:
23 |
24 | 1. The origin of this software must not be misrepresented; you must not
25 | claim that you wrote the original software. If you use this software
26 | in a product, an acknowledgment in the product documentation would be
27 | appreciated but is not required.
28 | 2. Altered source versions must be plainly marked as such, and must not be
29 | misrepresented as being the original software.
30 | 3. This notice may not be removed or altered from any source distribution.
31 |
32 | ---------------------------------------------------------------------------
33 |
34 | Changes
35 |
36 | See header of zip.h
37 |
38 | */
39 |
40 | #ifndef _zip12_H
41 | #define _zip12_H
42 |
43 | #ifdef __cplusplus
44 | extern "C" {
45 | #endif
46 |
47 | //#define HAVE_BZIP2
48 |
49 | #ifndef _ZLIB_H
50 | #include "zlib.h"
51 | #endif
52 |
53 | #ifndef _ZLIBIOAPI_H
54 | #include "ioapi.h"
55 | #endif
56 |
57 | #ifdef HAVE_BZIP2
58 | #include "bzlib.h"
59 | #endif
60 |
61 | #define Z_BZIP2ED 12
62 |
63 | #if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
64 | /* like the STRICT of WIN32, we define a pointer that cannot be converted
65 | from (void*) without cast */
66 | typedef struct TagzipFile__ { int unused; } zipFile__;
67 | typedef zipFile__ *zipFile;
68 | #else
69 | typedef voidp zipFile;
70 | #endif
71 |
72 | #define ZIP_OK (0)
73 | #define ZIP_EOF (0)
74 | #define ZIP_ERRNO (Z_ERRNO)
75 | #define ZIP_PARAMERROR (-102)
76 | #define ZIP_BADZIPFILE (-103)
77 | #define ZIP_INTERNALERROR (-104)
78 |
79 | #ifndef DEF_MEM_LEVEL
80 | # if MAX_MEM_LEVEL >= 8
81 | # define DEF_MEM_LEVEL 8
82 | # else
83 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL
84 | # endif
85 | #endif
86 | /* default memLevel */
87 |
88 | /* tm_zip contain date/time info */
89 | typedef struct tm_zip_s
90 | {
91 | uInt tm_sec; /* seconds after the minute - [0,59] */
92 | uInt tm_min; /* minutes after the hour - [0,59] */
93 | uInt tm_hour; /* hours since midnight - [0,23] */
94 | uInt tm_mday; /* day of the month - [1,31] */
95 | uInt tm_mon; /* months since January - [0,11] */
96 | uInt tm_year; /* years - [1980..2044] */
97 | } tm_zip;
98 |
99 | typedef struct
100 | {
101 | tm_zip tmz_date; /* date in understandable format */
102 | uLong dosDate; /* if dos_date == 0, tmu_date is used */
103 | /* uLong flag; */ /* general purpose bit flag 2 bytes */
104 |
105 | uLong internal_fa; /* internal file attributes 2 bytes */
106 | uLong external_fa; /* external file attributes 4 bytes */
107 | } zip_fileinfo;
108 |
109 | typedef const char* zipcharpc;
110 |
111 |
112 | #define APPEND_STATUS_CREATE (0)
113 | #define APPEND_STATUS_CREATEAFTER (1)
114 | #define APPEND_STATUS_ADDINZIP (2)
115 |
116 | extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append));
117 | extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append));
118 | /*
119 | Create a zipfile.
120 | pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on
121 | an Unix computer "zlib/zlib113.zip".
122 | if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
123 | will be created at the end of the file.
124 | (useful if the file contain a self extractor code)
125 | if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
126 | add files in existing zip (be sure you don't add file that doesn't exist)
127 | If the zipfile cannot be opened, the return value is NULL.
128 | Else, the return value is a zipFile Handle, usable with other function
129 | of this zip package.
130 | */
131 |
132 | /* Note : there is no delete function into a zipfile.
133 | If you want delete file into a zipfile, you must open a zipfile, and create another
134 | Of couse, you can use RAW reading and writing to copy the file you did not want delte
135 | */
136 |
137 | extern zipFile ZEXPORT zipOpen2 OF((const char *pathname,
138 | int append,
139 | zipcharpc* globalcomment,
140 | zlib_filefunc_def* pzlib_filefunc_def));
141 |
142 | extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname,
143 | int append,
144 | zipcharpc* globalcomment,
145 | zlib_filefunc64_def* pzlib_filefunc_def));
146 |
147 | extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
148 | const char* filename,
149 | const zip_fileinfo* zipfi,
150 | const void* extrafield_local,
151 | uInt size_extrafield_local,
152 | const void* extrafield_global,
153 | uInt size_extrafield_global,
154 | const char* comment,
155 | int method,
156 | int level));
157 |
158 | extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file,
159 | const char* filename,
160 | const zip_fileinfo* zipfi,
161 | const void* extrafield_local,
162 | uInt size_extrafield_local,
163 | const void* extrafield_global,
164 | uInt size_extrafield_global,
165 | const char* comment,
166 | int method,
167 | int level,
168 | int zip64));
169 |
170 | /*
171 | Open a file in the ZIP for writing.
172 | filename : the filename in zip (if NULL, '-' without quote will be used
173 | *zipfi contain supplemental information
174 | if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
175 | contains the extrafield data the the local header
176 | if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
177 | contains the extrafield data the the local header
178 | if comment != NULL, comment contain the comment string
179 | method contain the compression method (0 for store, Z_DEFLATED for deflate)
180 | level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
181 | zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
182 | this MUST be '1' if the uncompressed size is >= 0xffffffff.
183 |
184 | */
185 |
186 |
187 | extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file,
188 | const char* filename,
189 | const zip_fileinfo* zipfi,
190 | const void* extrafield_local,
191 | uInt size_extrafield_local,
192 | const void* extrafield_global,
193 | uInt size_extrafield_global,
194 | const char* comment,
195 | int method,
196 | int level,
197 | int raw));
198 |
199 |
200 | extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file,
201 | const char* filename,
202 | const zip_fileinfo* zipfi,
203 | const void* extrafield_local,
204 | uInt size_extrafield_local,
205 | const void* extrafield_global,
206 | uInt size_extrafield_global,
207 | const char* comment,
208 | int method,
209 | int level,
210 | int raw,
211 | int zip64));
212 | /*
213 | Same than zipOpenNewFileInZip, except if raw=1, we write raw file
214 | */
215 |
216 | extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
217 | const char* filename,
218 | const zip_fileinfo* zipfi,
219 | const void* extrafield_local,
220 | uInt size_extrafield_local,
221 | const void* extrafield_global,
222 | uInt size_extrafield_global,
223 | const char* comment,
224 | int method,
225 | int level,
226 | int raw,
227 | int windowBits,
228 | int memLevel,
229 | int strategy,
230 | const char* password,
231 | uLong crcForCrypting));
232 |
233 | extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file,
234 | const char* filename,
235 | const zip_fileinfo* zipfi,
236 | const void* extrafield_local,
237 | uInt size_extrafield_local,
238 | const void* extrafield_global,
239 | uInt size_extrafield_global,
240 | const char* comment,
241 | int method,
242 | int level,
243 | int raw,
244 | int windowBits,
245 | int memLevel,
246 | int strategy,
247 | const char* password,
248 | uLong crcForCrypting,
249 | int zip64
250 | ));
251 |
252 | /*
253 | Same than zipOpenNewFileInZip2, except
254 | windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
255 | password : crypting password (NULL for no crypting)
256 | crcForCrypting : crc of file to compress (needed for crypting)
257 | */
258 |
259 | extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file,
260 | const char* filename,
261 | const zip_fileinfo* zipfi,
262 | const void* extrafield_local,
263 | uInt size_extrafield_local,
264 | const void* extrafield_global,
265 | uInt size_extrafield_global,
266 | const char* comment,
267 | int method,
268 | int level,
269 | int raw,
270 | int windowBits,
271 | int memLevel,
272 | int strategy,
273 | const char* password,
274 | uLong crcForCrypting,
275 | uLong versionMadeBy,
276 | uLong flagBase
277 | ));
278 |
279 |
280 | extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file,
281 | const char* filename,
282 | const zip_fileinfo* zipfi,
283 | const void* extrafield_local,
284 | uInt size_extrafield_local,
285 | const void* extrafield_global,
286 | uInt size_extrafield_global,
287 | const char* comment,
288 | int method,
289 | int level,
290 | int raw,
291 | int windowBits,
292 | int memLevel,
293 | int strategy,
294 | const char* password,
295 | uLong crcForCrypting,
296 | uLong versionMadeBy,
297 | uLong flagBase,
298 | int zip64
299 | ));
300 | /*
301 | Same than zipOpenNewFileInZip4, except
302 | versionMadeBy : value for Version made by field
303 | flag : value for flag field (compression level info will be added)
304 | */
305 |
306 |
307 | extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
308 | const void* buf,
309 | unsigned len));
310 | /*
311 | Write data in the zipfile
312 | */
313 |
314 | extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
315 | /*
316 | Close the current file in the zipfile
317 | */
318 |
319 | extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
320 | uLong uncompressed_size,
321 | uLong crc32));
322 |
323 | extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file,
324 | ZPOS64_T uncompressed_size,
325 | uLong crc32));
326 |
327 | /*
328 | Close the current file in the zipfile, for file opened with
329 | parameter raw=1 in zipOpenNewFileInZip2
330 | uncompressed_size and crc32 are value for the uncompressed size
331 | */
332 |
333 | extern int ZEXPORT zipClose OF((zipFile file,
334 | const char* global_comment));
335 | /*
336 | Close the zipfile
337 | */
338 |
339 |
340 | extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader));
341 | /*
342 | zipRemoveExtraInfoBlock - Added by Mathias Svensson
343 |
344 | Remove extra information block from a extra information data for the local file header or central directory header
345 |
346 | It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.
347 |
348 | 0x0001 is the signature header for the ZIP64 extra information blocks
349 |
350 | usage.
351 | Remove ZIP64 Extra information from a central director extra field data
352 | zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001);
353 |
354 | Remove ZIP64 Extra information from a Local File Header extra field data
355 | zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);
356 | */
357 |
358 | #ifdef __cplusplus
359 | }
360 | #endif
361 |
362 | #endif /* _zip64_H */
363 |
--------------------------------------------------------------------------------
/src/ios/minizip/unzip.h:
--------------------------------------------------------------------------------
1 | /* unzip.h -- IO for uncompress .zip files using zlib
2 | Version 1.1, February 14h, 2010
3 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
4 |
5 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
6 |
7 | Modifications of Unzip for Zip64
8 | Copyright (C) 2007-2008 Even Rouault
9 |
10 | Modifications for Zip64 support on both zip and unzip
11 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
12 |
13 | For more info read MiniZip_info.txt
14 |
15 | ---------------------------------------------------------------------------------
16 |
17 | Condition of use and distribution are the same than zlib :
18 |
19 | This software is provided 'as-is', without any express or implied
20 | warranty. In no event will the authors be held liable for any damages
21 | arising from the use of this software.
22 |
23 | Permission is granted to anyone to use this software for any purpose,
24 | including commercial applications, and to alter it and redistribute it
25 | freely, subject to the following restrictions:
26 |
27 | 1. The origin of this software must not be misrepresented; you must not
28 | claim that you wrote the original software. If you use this software
29 | in a product, an acknowledgment in the product documentation would be
30 | appreciated but is not required.
31 | 2. Altered source versions must be plainly marked as such, and must not be
32 | misrepresented as being the original software.
33 | 3. This notice may not be removed or altered from any source distribution.
34 |
35 | ---------------------------------------------------------------------------------
36 |
37 | Changes
38 |
39 | See header of unzip64.c
40 |
41 | */
42 |
43 | #ifndef _unz64_H
44 | #define _unz64_H
45 |
46 | #ifdef __cplusplus
47 | extern "C" {
48 | #endif
49 |
50 | #ifndef _ZLIB_H
51 | #include "zlib.h"
52 | #endif
53 |
54 | #ifndef _ZLIBIOAPI_H
55 | #include "ioapi.h"
56 | #endif
57 |
58 | #ifdef HAVE_BZIP2
59 | #include "bzlib.h"
60 | #endif
61 |
62 | #define Z_BZIP2ED 12
63 |
64 | #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
65 | /* like the STRICT of WIN32, we define a pointer that cannot be converted
66 | from (void*) without cast */
67 | typedef struct TagunzFile__ { int unused; } unzFile__;
68 | typedef unzFile__ *unzFile;
69 | #else
70 | typedef voidp unzFile;
71 | #endif
72 |
73 |
74 | #define UNZ_OK (0)
75 | #define UNZ_END_OF_LIST_OF_FILE (-100)
76 | #define UNZ_ERRNO (Z_ERRNO)
77 | #define UNZ_EOF (0)
78 | #define UNZ_PARAMERROR (-102)
79 | #define UNZ_BADZIPFILE (-103)
80 | #define UNZ_INTERNALERROR (-104)
81 | #define UNZ_CRCERROR (-105)
82 |
83 | /* tm_unz contain date/time info */
84 | typedef struct tm_unz_s
85 | {
86 | uInt tm_sec; /* seconds after the minute - [0,59] */
87 | uInt tm_min; /* minutes after the hour - [0,59] */
88 | uInt tm_hour; /* hours since midnight - [0,23] */
89 | uInt tm_mday; /* day of the month - [1,31] */
90 | uInt tm_mon; /* months since January - [0,11] */
91 | uInt tm_year; /* years - [1980..2044] */
92 | } tm_unz;
93 |
94 | /* unz_global_info structure contain global data about the ZIPfile
95 | These data comes from the end of central dir */
96 | typedef struct unz_global_info64_s
97 | {
98 | ZPOS64_T number_entry; /* total number of entries in
99 | the central dir on this disk */
100 | uLong size_comment; /* size of the global comment of the zipfile */
101 | } unz_global_info64;
102 |
103 | typedef struct unz_global_info_s
104 | {
105 | uLong number_entry; /* total number of entries in
106 | the central dir on this disk */
107 | uLong size_comment; /* size of the global comment of the zipfile */
108 | } unz_global_info;
109 |
110 | /* unz_file_info contain information about a file in the zipfile */
111 | typedef struct unz_file_info64_s
112 | {
113 | uLong version; /* version made by 2 bytes */
114 | uLong version_needed; /* version needed to extract 2 bytes */
115 | uLong flag; /* general purpose bit flag 2 bytes */
116 | uLong compression_method; /* compression method 2 bytes */
117 | uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
118 | uLong crc; /* crc-32 4 bytes */
119 | ZPOS64_T compressed_size; /* compressed size 8 bytes */
120 | ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */
121 | uLong size_filename; /* filename length 2 bytes */
122 | uLong size_file_extra; /* extra field length 2 bytes */
123 | uLong size_file_comment; /* file comment length 2 bytes */
124 |
125 | uLong disk_num_start; /* disk number start 2 bytes */
126 | uLong internal_fa; /* internal file attributes 2 bytes */
127 | uLong external_fa; /* external file attributes 4 bytes */
128 |
129 | tm_unz tmu_date;
130 | } unz_file_info64;
131 |
132 | typedef struct unz_file_info_s
133 | {
134 | uLong version; /* version made by 2 bytes */
135 | uLong version_needed; /* version needed to extract 2 bytes */
136 | uLong flag; /* general purpose bit flag 2 bytes */
137 | uLong compression_method; /* compression method 2 bytes */
138 | uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
139 | uLong crc; /* crc-32 4 bytes */
140 | uLong compressed_size; /* compressed size 4 bytes */
141 | uLong uncompressed_size; /* uncompressed size 4 bytes */
142 | uLong size_filename; /* filename length 2 bytes */
143 | uLong size_file_extra; /* extra field length 2 bytes */
144 | uLong size_file_comment; /* file comment length 2 bytes */
145 |
146 | uLong disk_num_start; /* disk number start 2 bytes */
147 | uLong internal_fa; /* internal file attributes 2 bytes */
148 | uLong external_fa; /* external file attributes 4 bytes */
149 |
150 | tm_unz tmu_date;
151 | } unz_file_info;
152 |
153 | extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
154 | const char* fileName2,
155 | int iCaseSensitivity));
156 | /*
157 | Compare two filename (fileName1,fileName2).
158 | If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
159 | If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
160 | or strcasecmp)
161 | If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
162 | (like 1 on Unix, 2 on Windows)
163 | */
164 |
165 |
166 | extern unzFile ZEXPORT unzOpen OF((const char *path));
167 | extern unzFile ZEXPORT unzOpen64 OF((const void *path));
168 | /*
169 | Open a Zip file. path contain the full pathname (by example,
170 | on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
171 | "zlib/zlib113.zip".
172 | If the zipfile cannot be opened (file don't exist or in not valid), the
173 | return value is NULL.
174 | Else, the return value is a unzFile Handle, usable with other function
175 | of this unzip package.
176 | the "64" function take a const void* pointer, because the path is just the
177 | value passed to the open64_file_func callback.
178 | Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
179 | is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
180 | does not describe the reality
181 | */
182 |
183 |
184 | extern unzFile ZEXPORT unzOpen2 OF((const char *path,
185 | zlib_filefunc_def* pzlib_filefunc_def));
186 | /*
187 | Open a Zip file, like unzOpen, but provide a set of file low level API
188 | for read/write the zip file (see ioapi.h)
189 | */
190 |
191 | extern unzFile ZEXPORT unzOpen2_64 OF((const void *path,
192 | zlib_filefunc64_def* pzlib_filefunc_def));
193 | /*
194 | Open a Zip file, like unz64Open, but provide a set of file low level API
195 | for read/write the zip file (see ioapi.h)
196 | */
197 |
198 | extern int ZEXPORT unzClose OF((unzFile file));
199 | /*
200 | Close a ZipFile opened with unzipOpen.
201 | If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
202 | these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
203 | return UNZ_OK if there is no problem. */
204 |
205 | extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
206 | unz_global_info *pglobal_info));
207 |
208 | extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,
209 | unz_global_info64 *pglobal_info));
210 | /*
211 | Write info about the ZipFile in the *pglobal_info structure.
212 | No preparation of the structure is needed
213 | return UNZ_OK if there is no problem. */
214 |
215 |
216 | extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
217 | char *szComment,
218 | uLong uSizeBuf));
219 | /*
220 | Get the global comment string of the ZipFile, in the szComment buffer.
221 | uSizeBuf is the size of the szComment buffer.
222 | return the number of byte copied or an error code <0
223 | */
224 |
225 |
226 | /***************************************************************************/
227 | /* Unzip package allow you browse the directory of the zipfile */
228 |
229 | extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
230 | /*
231 | Set the current file of the zipfile to the first file.
232 | return UNZ_OK if there is no problem
233 | */
234 |
235 | extern int ZEXPORT unzGoToNextFile OF((unzFile file));
236 | /*
237 | Set the current file of the zipfile to the next file.
238 | return UNZ_OK if there is no problem
239 | return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
240 | */
241 |
242 | extern int ZEXPORT unzLocateFile OF((unzFile file,
243 | const char *szFileName,
244 | int iCaseSensitivity));
245 | /*
246 | Try locate the file szFileName in the zipfile.
247 | For the iCaseSensitivity signification, see unzStringFileNameCompare
248 |
249 | return value :
250 | UNZ_OK if the file is found. It becomes the current file.
251 | UNZ_END_OF_LIST_OF_FILE if the file is not found
252 | */
253 |
254 |
255 | /* ****************************************** */
256 | /* Ryan supplied functions */
257 | /* unz_file_info contain information about a file in the zipfile */
258 | typedef struct unz_file_pos_s
259 | {
260 | uLong pos_in_zip_directory; /* offset in zip file directory */
261 | uLong num_of_file; /* # of file */
262 | } unz_file_pos;
263 |
264 | extern int ZEXPORT unzGetFilePos(
265 | unzFile file,
266 | unz_file_pos* file_pos);
267 |
268 | extern int ZEXPORT unzGoToFilePos(
269 | unzFile file,
270 | unz_file_pos* file_pos);
271 |
272 | typedef struct unz64_file_pos_s
273 | {
274 | ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */
275 | ZPOS64_T num_of_file; /* # of file */
276 | } unz64_file_pos;
277 |
278 | extern int ZEXPORT unzGetFilePos64(
279 | unzFile file,
280 | unz64_file_pos* file_pos);
281 |
282 | extern int ZEXPORT unzGoToFilePos64(
283 | unzFile file,
284 | const unz64_file_pos* file_pos);
285 |
286 | /* ****************************************** */
287 |
288 | extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,
289 | unz_file_info64 *pfile_info,
290 | char *szFileName,
291 | uLong fileNameBufferSize,
292 | void *extraField,
293 | uLong extraFieldBufferSize,
294 | char *szComment,
295 | uLong commentBufferSize));
296 |
297 | extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
298 | unz_file_info *pfile_info,
299 | char *szFileName,
300 | uLong fileNameBufferSize,
301 | void *extraField,
302 | uLong extraFieldBufferSize,
303 | char *szComment,
304 | uLong commentBufferSize));
305 | /*
306 | Get Info about the current file
307 | if pfile_info!=NULL, the *pfile_info structure will contain somes info about
308 | the current file
309 | if szFileName!=NULL, the filemane string will be copied in szFileName
310 | (fileNameBufferSize is the size of the buffer)
311 | if extraField!=NULL, the extra field information will be copied in extraField
312 | (extraFieldBufferSize is the size of the buffer).
313 | This is the Central-header version of the extra field
314 | if szComment!=NULL, the comment string of the file will be copied in szComment
315 | (commentBufferSize is the size of the buffer)
316 | */
317 |
318 |
319 | /** Addition for GDAL : START */
320 |
321 | extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
322 |
323 | /** Addition for GDAL : END */
324 |
325 |
326 | /***************************************************************************/
327 | /* for reading the content of the current zipfile, you can open it, read data
328 | from it, and close it (you can close it before reading all the file)
329 | */
330 |
331 | extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
332 | /*
333 | Open for reading data the current file in the zipfile.
334 | If there is no error, the return value is UNZ_OK.
335 | */
336 |
337 | extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
338 | const char* password));
339 | /*
340 | Open for reading data the current file in the zipfile.
341 | password is a crypting password
342 | If there is no error, the return value is UNZ_OK.
343 | */
344 |
345 | extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
346 | int* method,
347 | int* level,
348 | int raw));
349 | /*
350 | Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
351 | if raw==1
352 | *method will receive method of compression, *level will receive level of
353 | compression
354 | note : you can set level parameter as NULL (if you did not want known level,
355 | but you CANNOT set method parameter as NULL
356 | */
357 |
358 | extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
359 | int* method,
360 | int* level,
361 | int raw,
362 | const char* password));
363 | /*
364 | Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
365 | if raw==1
366 | *method will receive method of compression, *level will receive level of
367 | compression
368 | note : you can set level parameter as NULL (if you did not want known level,
369 | but you CANNOT set method parameter as NULL
370 | */
371 |
372 |
373 | extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
374 | /*
375 | Close the file in zip opened with unzOpenCurrentFile
376 | Return UNZ_CRCERROR if all the file was read but the CRC is not good
377 | */
378 |
379 | extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
380 | voidp buf,
381 | unsigned len));
382 | /*
383 | Read bytes from the current file (opened by unzOpenCurrentFile)
384 | buf contain buffer where data must be copied
385 | len the size of buf.
386 |
387 | return the number of byte copied if somes bytes are copied
388 | return 0 if the end of file was reached
389 | return <0 with error code if there is an error
390 | (UNZ_ERRNO for IO error, or zLib error for uncompress error)
391 | */
392 |
393 | extern z_off_t ZEXPORT unztell OF((unzFile file));
394 |
395 | extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
396 | /*
397 | Give the current position in uncompressed data
398 | */
399 |
400 | extern int ZEXPORT unzeof OF((unzFile file));
401 | /*
402 | return 1 if the end of file was reached, 0 elsewhere
403 | */
404 |
405 | extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
406 | voidp buf,
407 | unsigned len));
408 | /*
409 | Read extra field from the current file (opened by unzOpenCurrentFile)
410 | This is the local-header version of the extra field (sometimes, there is
411 | more info in the local-header version than in the central-header)
412 |
413 | if buf==NULL, it return the size of the local extra field
414 |
415 | if buf!=NULL, len is the size of the buffer, the extra header is copied in
416 | buf.
417 | the return value is the number of bytes copied in buf, or (if <0)
418 | the error code
419 | */
420 |
421 | /***************************************************************************/
422 |
423 | /* Get the current file offset */
424 | extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
425 | extern uLong ZEXPORT unzGetOffset (unzFile file);
426 |
427 | /* Set the current file offset */
428 | extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
429 | extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
430 |
431 |
432 |
433 | #ifdef __cplusplus
434 | }
435 | #endif
436 |
437 | #endif /* _unz64_H */
438 |
--------------------------------------------------------------------------------
/src/wp8/Unzip.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.IO.IsolatedStorage;
6 | using System.Linq;
7 | using System.Runtime.Serialization;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows;
11 | using System.Windows.Resources;
12 |
13 | namespace WPCordovaClassLib.Cordova.Commands
14 | {
15 | public class UnZip : BaseCommand
16 | {
17 | // Sync strategy codes
18 | public const int Replace = 1;
19 | public const int Merge = 2;
20 |
21 | ///
22 | /// Represents a singular progress event to be passed back to javascript
23 | ///
24 | [DataContract]
25 | public class FileUnzipProgress
26 | {
27 | ///
28 | /// amount loaded
29 | ///
30 | [DataMember(Name = "loaded", IsRequired = true)]
31 | public long Loaded { get; set; }
32 | ///
33 | /// Total
34 | ///
35 | [DataMember(Name = "total", IsRequired = false)]
36 | public long Total { get; set; }
37 |
38 | public FileUnzipProgress(long total = 0, long loaded = 0)
39 | {
40 | Loaded = loaded;
41 | Total = total;
42 | }
43 | }
44 |
45 | public void unzip(string srcFilePath, string destPath, int type)
46 | {
47 | using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
48 | {
49 | // DEBUG here to copy file from dll to isostore ...
50 | // this is only really needed if you want to test with a file in your package/project
51 | StreamResourceInfo fileResourceStreamInfo = Application.GetResourceStream(new Uri(srcFilePath, UriKind.Relative));
52 | if (fileResourceStreamInfo != null)
53 | {
54 | using (BinaryReader br = new BinaryReader(fileResourceStreamInfo.Stream))
55 | {
56 | byte[] data = br.ReadBytes((int)fileResourceStreamInfo.Stream.Length);
57 | // This will truncate/overwrite an existing file, or
58 | using (IsolatedStorageFileStream outFile = appStorage.OpenFile(srcFilePath, FileMode.Create))
59 | {
60 | using (var writer = new BinaryWriter(outFile))
61 | {
62 | writer.Write(data);
63 | }
64 | }
65 | }
66 | }
67 |
68 | if(type == Replace)
69 | {
70 | DeleteDirectoryRecursively(appStorage, destPath);
71 | }
72 |
73 | IsolatedStorageFileStream zipStream = null;
74 | ZipArchive zipArch = null;
75 |
76 | try
77 | {
78 | zipStream = new IsolatedStorageFileStream(srcFilePath, FileMode.Open, FileAccess.Read, appStorage);
79 | }
80 | catch (Exception)
81 | {
82 | Debug.WriteLine("File not found :: " + srcFilePath);
83 | return;
84 | }
85 |
86 | if (zipStream != null)
87 | {
88 | zipArch = new ZipArchive(zipStream);
89 | }
90 |
91 | if (zipArch != null)
92 | {
93 | int totalFiles = zipArch.FileNames.Count();
94 | int current = 0;
95 | try
96 | {
97 | foreach (string filename in zipArch.FileNames)
98 | {
99 | string destFilePath = destPath + "/" + filename;
100 |
101 | string directoryName = getDirectoryName(destFilePath);
102 |
103 | //Debug.WriteLine("upacking file : " + filename + " to : " + destFilePath);
104 |
105 | if (!appStorage.DirectoryExists(directoryName))
106 | {
107 | appStorage.CreateDirectory(directoryName);
108 | }
109 |
110 |
111 |
112 | using (Stream readStream = zipArch.GetFileStream(filename))
113 | {
114 | if (readStream != null)
115 | {
116 | using (FileStream outStream = new IsolatedStorageFileStream(destFilePath, FileMode.Create, FileAccess.Write, appStorage))
117 | {
118 | WriteStreamToPath(readStream, outStream);
119 | FileUnzipProgress progEvt = new FileUnzipProgress(totalFiles, current++);
120 | }
121 | }
122 | }
123 | }
124 | zipStream.Close();
125 |
126 | }
127 | catch (Exception)
128 | {
129 | Debug.WriteLine("File not found :: " + srcFilePath);
130 | }
131 | }
132 | }
133 | }
134 |
135 | private void WriteStreamToPath(Stream readStream, Stream outStream)
136 | {
137 |
138 | long totalBytes = readStream.Length;
139 | int bytesRead = 0;
140 |
141 | using (BinaryReader reader = new BinaryReader(readStream))
142 | {
143 | using (BinaryWriter writer = new BinaryWriter(outStream))
144 | {
145 | int BUFFER_SIZE = 1024;
146 | byte[] buffer;
147 |
148 | while (true)
149 | {
150 | buffer = reader.ReadBytes(BUFFER_SIZE);
151 | bytesRead += buffer.Length;
152 | if (buffer.Length > 0)
153 | {
154 | writer.Write(buffer);
155 | }
156 | else
157 | {
158 | writer.Close();
159 | reader.Close();
160 | outStream.Close();
161 | break;
162 | }
163 | }
164 | }
165 | }
166 |
167 | }
168 |
169 | // Gets the full path without the filename
170 | private string getDirectoryName(String filePath)
171 | {
172 | string directoryName;
173 | try
174 | {
175 | directoryName = filePath.Substring(0, filePath.LastIndexOf('/'));
176 | }
177 | catch
178 | {
179 | directoryName = "";
180 | }
181 | return directoryName;
182 | }
183 |
184 | // helper function from: http://stackoverflow.com/questions/18422331/easy-way-to-recursively-delete-directories-in-isolatedstorage-on-wp7-8
185 | private void DeleteDirectoryRecursively(IsolatedStorageFile storageFile, String dirName)
186 | {
187 | try
188 | {
189 | String pattern = dirName + @"\*";
190 | String[] files = storageFile.GetFileNames(pattern);
191 | foreach (var fName in files)
192 | {
193 | storageFile.DeleteFile(Path.Combine(dirName, fName));
194 | }
195 | String[] dirs = storageFile.GetDirectoryNames(pattern);
196 | foreach (var dName in dirs)
197 | {
198 | DeleteDirectoryRecursively(storageFile, Path.Combine(dirName, dName));
199 | }
200 | if (storageFile.DirectoryExists(dirName))
201 | {
202 | storageFile.DeleteDirectory(dirName);
203 | }
204 | }
205 | catch(Exception e)
206 | {
207 | Debug.WriteLine("Unable to delete directory : " + dirName);
208 | }
209 | }
210 |
211 | ///
212 | /// Class used for storing file entry information when
213 | /// parsing the central file directory.
214 | ///
215 | private class ZipArchiveEntry
216 | {
217 | public string Filename;
218 | public int FileStart;
219 | public int CompressedLength;
220 | public int Length;
221 | public int CRC32;
222 | }
223 |
224 | private class ZipArchive : IDisposable
225 | {
226 | private const int CENTRAL_FILE_HDR_SIG = 0x02014b50;
227 | private const int END_CENTRAL_DIR_SIG = 0x06054b50;
228 |
229 | private Stream ZipStream;
230 | private List _fileEntries;
231 |
232 | public ZipArchive(Stream zipFileStream)
233 | {
234 | if (!zipFileStream.CanSeek)
235 | {
236 | throw new NotSupportedException("zipFileStream must support seeking");
237 | }
238 | else
239 | {
240 | ZipStream = zipFileStream;
241 | }
242 | }
243 |
244 | public List FileEntries
245 | {
246 | get
247 | {
248 | if (_fileEntries == null)
249 | {
250 | InflateDirectory();
251 | }
252 | return _fileEntries;
253 | }
254 | }
255 |
256 |
257 | ///
258 | /// Gets the file stream for the specified file. Returns null if the file could not be found.
259 | ///
260 | /// The filename.
261 | /// Stream to file inside zip stream
262 | public Stream GetFileStream(string filename)
263 | {
264 | long position = ZipStream.Position;
265 | ZipStream.Seek(0, SeekOrigin.Begin);
266 | Uri fileUri = new Uri(filename, UriKind.Relative);
267 | StreamResourceInfo info = new StreamResourceInfo(ZipStream, null);
268 | StreamResourceInfo stream = System.Windows.Application.GetResourceStream(info, fileUri);
269 | ZipStream.Position = position;
270 | if (stream != null)
271 | {
272 | return stream.Stream;
273 | }
274 | return null;
275 | }
276 |
277 | ///
278 | /// Gets a list of file names embedded in the zip file.
279 | ///
280 | /// The stream for a zip file.
281 | /// List of file names
282 | public IEnumerable FileNames
283 | {
284 | get
285 | {
286 | return (from entry in FileEntries
287 | where (!entry.Filename.EndsWith("/") &&
288 | !entry.Filename.StartsWith("__MACOSX/"))
289 | select entry.Filename);
290 | }
291 | }
292 |
293 | ///
294 | /// Gets a list of directories embedded in the zip file
295 | ///
296 | public IEnumerable DirectoriesName
297 | {
298 | get
299 | {
300 | return (from entry in FileEntries
301 | where (entry.Filename.EndsWith("/")
302 | && !entry.Filename.StartsWith("__MACOSX/"))
303 | select entry.Filename);
304 | }
305 | }
306 |
307 | /***************************************************
308 | 4.3.16 End of central directory record:
309 | end of central dir signature 4 bytes (0x06054b50)
310 | number of this disk 2 bytes
311 | number of the disk with the
312 | start of the central directory 2 bytes
313 | total number of entries in the
314 | central directory on this disk 2 bytes
315 | total number of entries in
316 | the central directory 2 bytes
317 | size of the central directory 4 bytes
318 | offset of start of central
319 | directory with respect to
320 | the starting disk number 4 bytes
321 | .ZIP file comment length 2 bytes
322 | .ZIP file comment (variable size)
323 | */
324 |
325 | /***************************************************
326 | File header:
327 | central file header signature 4 bytes (0x02014b50)
328 | version made by 2 bytes
329 | version needed to extract 2 bytes
330 | general purpose bit flag 2 bytes
331 | compression method 2 bytes
332 | last mod file time 2 bytes
333 | last mod file date 2 bytes
334 | crc-32 4 bytes
335 | compressed size 4 bytes
336 | uncompressed size 4 bytes
337 | file name length 2 bytes
338 | extra field length 2 bytes
339 | file comment length 2 bytes
340 | disk number start 2 bytes
341 | internal file attributes 2 bytes
342 | external file attributes 4 bytes
343 | relative offset of local header 4 bytes
344 | file name (variable size)
345 | extra field (variable size)
346 | file comment (variable size)
347 | */
348 |
349 |
350 | private List InflateDirectory()
351 | {
352 | _fileEntries = new List();
353 |
354 | BinaryReader reader = new BinaryReader(ZipStream);
355 |
356 | reader.BaseStream.Seek(-4, SeekOrigin.End);
357 | // skip back
358 | while (reader.ReadInt32() != END_CENTRAL_DIR_SIG)
359 | {
360 | reader.BaseStream.Seek(-5, SeekOrigin.Current);
361 | }
362 | // skip over number of this disk, number of the disk with dir start, total number of entries on this disk
363 | reader.BaseStream.Seek(6, SeekOrigin.Current);
364 | short entryCount = reader.ReadInt16();
365 | int directorySize = reader.ReadInt32();
366 | int directoryStart = reader.ReadInt32();
367 | reader.BaseStream.Seek(directoryStart, SeekOrigin.Begin);
368 | bool doRebuild = false;
369 |
370 | for (int i = 0; i < entryCount; i++)
371 | {
372 | if (reader.ReadInt32() == CENTRAL_FILE_HDR_SIG)
373 | {
374 | ZipArchiveEntry zipEntry = new ZipArchiveEntry();
375 |
376 | reader.BaseStream.Seek(4, SeekOrigin.Current);
377 | short flags = reader.ReadInt16(); // read general purpose bit flag
378 |
379 | if ((flags & 8) > 0) //Silverlight doesn't like this format. We'll "fix it" further below
380 | {
381 | doRebuild = true;
382 | }
383 | // skip: compression method, last mod file time, last mod file date
384 | reader.BaseStream.Seek(6, SeekOrigin.Current);
385 |
386 | zipEntry.CRC32 = reader.ReadInt32();
387 | zipEntry.CompressedLength = reader.ReadInt32();
388 | zipEntry.Length = reader.ReadInt32();
389 |
390 | short fileNameLength = reader.ReadInt16();
391 | short extraFieldLength = reader.ReadInt16();
392 | short fileCommentLength = reader.ReadInt16();
393 |
394 | // skip disk number start, internal file attr, ext file attr
395 | reader.BaseStream.Seek(8, SeekOrigin.Current);
396 |
397 | zipEntry.FileStart = reader.ReadInt32();
398 | zipEntry.Filename = new string(reader.ReadChars(fileNameLength));
399 | _fileEntries.Add(zipEntry);
400 |
401 | reader.BaseStream.Seek(extraFieldLength + fileCommentLength, SeekOrigin.Current);
402 | }
403 | }
404 | if (doRebuild)
405 | {
406 | // if file size is reported after the compressed data the filestream is unsupported by silverlight
407 | MemoryStream newZipStream = new MemoryStream();
408 | BinaryWriter writer = new BinaryWriter(newZipStream);
409 |
410 | RebuildEntries(ref reader, ref writer);
411 |
412 | // rewind
413 | reader.BaseStream.Seek(directoryStart, SeekOrigin.Begin);
414 | //Rebuild directory
415 | RebuildDirectory(ref reader, ref writer);
416 |
417 | writer.Write(reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)));
418 | ZipStream = newZipStream; //Swap to use our newly cleaned stream
419 | }
420 | return _fileEntries;
421 | }
422 |
423 | private void RebuildDirectory(ref BinaryReader reader, ref BinaryWriter writer)
424 | {
425 | for (int i = 0; i < _fileEntries.Count; i++)
426 | {
427 | writer.Write(reader.ReadBytes(8));
428 | byte flag = reader.ReadByte();
429 | writer.Write((byte)(0xF7 & flag)); //set 3rd hobbit to 0 for new format
430 | writer.Write(reader.ReadBytes(19));
431 | short filenamelength = reader.ReadInt16();
432 | writer.Write(filenamelength);
433 | short extrafieldlength = reader.ReadInt16();
434 | writer.Write(extrafieldlength);
435 | short filecommentlength = reader.ReadInt16();
436 | writer.Write(filecommentlength);
437 | writer.Write(reader.ReadBytes(8));
438 | writer.Write(_fileEntries[i].FileStart);
439 | reader.BaseStream.Seek(4, SeekOrigin.Current);
440 | writer.Write(reader.ReadBytes(filenamelength + extrafieldlength + filecommentlength));
441 | }
442 | }
443 |
444 | private void RebuildEntries(ref BinaryReader reader, ref BinaryWriter writer)
445 | {
446 | //Rebuild file entries
447 | foreach (ZipArchiveEntry entry in _fileEntries)
448 | {
449 | ZipArchiveEntry e = entry;
450 | reader.BaseStream.Seek(entry.FileStart, SeekOrigin.Begin);
451 | e.FileStart = (int)writer.BaseStream.Position;
452 | writer.Write(reader.ReadBytes(6));
453 |
454 | short flag = reader.ReadInt16();
455 | writer.Write((short)(0xF7 & flag)); //set 3rd hobbit to 0 for new format
456 | writer.Write(reader.ReadBytes(6));
457 | writer.Write(entry.CRC32);
458 | writer.Write(entry.CompressedLength);
459 | writer.Write(entry.Length);
460 | writer.Write((short)entry.Filename.Length);
461 | reader.BaseStream.Seek(14, SeekOrigin.Current);
462 | short fieldLength = reader.ReadInt16();
463 | writer.Write(fieldLength);
464 | writer.Write(reader.ReadBytes(entry.Filename.Length + fieldLength + entry.CompressedLength));
465 | }
466 | }
467 |
468 | #region IDisposable Members
469 |
470 | public void Dispose()
471 | {
472 | if (ZipStream != null)
473 | {
474 | ZipStream.Dispose();
475 | }
476 | }
477 |
478 | #endregion
479 | }
480 | }
481 | }
--------------------------------------------------------------------------------