Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
D
douban-api-proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
captainwong
douban-api-proxy
Commits
a159bb0b
Commit
a159bb0b
authored
Sep 17, 2017
by
OzzieIsaacs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code Csmetics kthoom integration
parent
5b9b36f9
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1301 additions
and
1301 deletions
+1301
-1301
archive.js
cps/static/js/archive.js
+326
-325
io.js
cps/static/js/io.js
+465
-466
unzip.js
cps/static/js/unzip.js
+510
-510
No files found.
cps/static/js/archive.js
View file @
a159bb0b
...
...
@@ -13,341 +13,342 @@ bitjs.archive = bitjs.archive || {};
(
function
()
{
// ===========================================================================
// Stolen from Closure because it's the best way to do Java-like inheritance.
bitjs
.
base
=
function
(
me
,
opt_methodName
,
var_args
)
{
var
caller
=
arguments
.
callee
.
caller
;
if
(
caller
.
superClass_
)
{
// This is a constructor. Call the superclass constructor.
return
caller
.
superClass_
.
constructor
.
apply
(
me
,
Array
.
prototype
.
slice
.
call
(
arguments
,
1
));
}
var
args
=
Array
.
prototype
.
slice
.
call
(
arguments
,
2
);
var
foundCaller
=
false
;
for
(
var
ctor
=
me
.
constructor
;
ctor
;
ctor
=
ctor
.
superClass_
&&
ctor
.
superClass_
.
constructor
)
{
if
(
ctor
.
prototype
[
opt_methodName
]
===
caller
)
{
foundCaller
=
true
;
}
else
if
(
foundCaller
)
{
return
ctor
.
prototype
[
opt_methodName
].
apply
(
me
,
args
);
}
}
// If we did not find the caller in the prototype chain,
// then one of two things happened:
// 1) The caller is an instance method.
// 2) This method was not called by the right caller.
if
(
me
[
opt_methodName
]
===
caller
)
{
return
me
.
constructor
.
prototype
[
opt_methodName
].
apply
(
me
,
args
);
}
else
{
throw
Error
(
'goog.base called from a method of one name '
+
'to a method of a different name'
);
}
};
bitjs
.
inherits
=
function
(
childCtor
,
parentCtor
)
{
/** @constructor */
function
tempCtor
()
{};
tempCtor
.
prototype
=
parentCtor
.
prototype
;
childCtor
.
superClass_
=
parentCtor
.
prototype
;
childCtor
.
prototype
=
new
tempCtor
();
childCtor
.
prototype
.
constructor
=
childCtor
;
};
// ===========================================================================
/**
* An unarchive event.
*
* @param {string} type The event type.
* @constructor
*/
bitjs
.
archive
.
UnarchiveEvent
=
function
(
type
)
{
/**
* The event type.
*
* @type {string}
*/
this
.
type
=
type
;
};
/**
* The UnarchiveEvent types.
*/
bitjs
.
archive
.
UnarchiveEvent
.
Type
=
{
START
:
'start'
,
PROGRESS
:
'progress'
,
EXTRACT
:
'extract'
,
FINISH
:
'finish'
,
INFO
:
'info'
,
ERROR
:
'error'
};
/**
* Useful for passing info up to the client (for debugging).
*
* @param {string} msg The info message.
*/
bitjs
.
archive
.
UnarchiveInfoEvent
=
function
(
msg
)
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
INFO
);
/**
* The information message.
*
* @type {string}
*/
this
.
msg
=
msg
;
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveInfoEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* An unrecoverable error has occured.
*
* @param {string} msg The error message.
*/
bitjs
.
archive
.
UnarchiveErrorEvent
=
function
(
msg
)
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
ERROR
);
/**
* The information message.
*
* @type {string}
*/
this
.
msg
=
msg
;
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveErrorEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* Start event.
*
* @param {string} msg The info message.
*/
bitjs
.
archive
.
UnarchiveStartEvent
=
function
()
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
START
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveStartEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* Finish event.
*
* @param {string} msg The info message.
*/
bitjs
.
archive
.
UnarchiveFinishEvent
=
function
()
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
FINISH
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveFinishEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* Progress event.
*/
bitjs
.
archive
.
UnarchiveProgressEvent
=
function
(
currentFilename
,
currentFileNumber
,
currentBytesUnarchivedInFile
,
currentBytesUnarchived
,
totalUncompressedBytesInArchive
,
totalFilesInArchive
)
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
PROGRESS
);
this
.
currentFilename
=
currentFilename
;
this
.
currentFileNumber
=
currentFileNumber
;
this
.
currentBytesUnarchivedInFile
=
currentBytesUnarchivedInFile
;
this
.
totalFilesInArchive
=
totalFilesInArchive
;
this
.
currentBytesUnarchived
=
currentBytesUnarchived
;
this
.
totalUncompressedBytesInArchive
=
totalUncompressedBytesInArchive
;
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveProgressEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* All extracted files returned by an Unarchiver will implement
* the following interface:
*
* interface UnarchivedFile {
* string filename
* TypedArray fileData
* }
*
*/
/**
* Extract event.
*/
bitjs
.
archive
.
UnarchiveExtractEvent
=
function
(
unarchivedFile
)
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
EXTRACT
);
/**
* @type {UnarchivedFile}
*/
this
.
unarchivedFile
=
unarchivedFile
;
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveExtractEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* Base class for all Unarchivers.
*
* @param {ArrayBuffer} arrayBuffer The Array Buffer.
* @param {string} opt_pathToBitJS Optional string for where the BitJS files are located.
* @constructor
*/
bitjs
.
archive
.
Unarchiver
=
function
(
arrayBuffer
,
opt_pathToBitJS
)
{
/**
* The ArrayBuffer object.
* @type {ArrayBuffer}
* @protected
*/
this
.
ab
=
arrayBuffer
;
/**
* The path to the BitJS files.
* @type {string}
* @private
*/
this
.
pathToBitJS_
=
opt_pathToBitJS
||
''
;
/**
* A map from event type to an array of listeners.
* @type {Map.<string, Array>}
*/
this
.
listeners_
=
{};
for
(
var
type
in
bitjs
.
archive
.
UnarchiveEvent
.
Type
)
{
this
.
listeners_
[
bitjs
.
archive
.
UnarchiveEvent
.
Type
[
type
]]
=
[];
}
};
/**
* Private web worker initialized during start().
* @type {Worker}
* @private
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
worker_
=
null
;
/**
* This method must be overridden by the subclass to return the script filename.
* @return {string} The script filename.
* @protected.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
getScriptFileName
=
function
()
{
throw
'Subclasses of AbstractUnarchiver must overload getScriptFileName()'
;
};
/**
* Adds an event listener for UnarchiveEvents.
*
* @param {string} Event type.
* @param {function} An event handler function.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
addEventListener
=
function
(
type
,
listener
)
{
if
(
type
in
this
.
listeners_
)
{
if
(
this
.
listeners_
[
type
].
indexOf
(
listener
)
==
-
1
)
{
this
.
listeners_
[
type
].
push
(
listener
);
}
}
};
// ===========================================================================
// Stolen from Closure because it's the best way to do Java-like inheritance.
bitjs
.
base
=
function
(
me
,
opt_methodName
,
var_args
)
{
var
caller
=
arguments
.
callee
.
caller
;
if
(
caller
.
superClass_
)
{
// This is a constructor. Call the superclass constructor.
return
caller
.
superClass_
.
constructor
.
apply
(
me
,
Array
.
prototype
.
slice
.
call
(
arguments
,
1
));
}
var
args
=
Array
.
prototype
.
slice
.
call
(
arguments
,
2
);
var
foundCaller
=
false
;
for
(
var
ctor
=
me
.
constructor
;
ctor
;
ctor
=
ctor
.
superClass_
&&
ctor
.
superClass_
.
constructor
)
{
if
(
ctor
.
prototype
[
opt_methodName
]
===
caller
)
{
foundCaller
=
true
;
}
else
if
(
foundCaller
)
{
return
ctor
.
prototype
[
opt_methodName
].
apply
(
me
,
args
);
}
}
// If we did not find the caller in the prototype chain,
// then one of two things happened:
// 1) The caller is an instance method.
// 2) This method was not called by the right caller.
if
(
me
[
opt_methodName
]
===
caller
)
{
return
me
.
constructor
.
prototype
[
opt_methodName
].
apply
(
me
,
args
);
}
else
{
throw
Error
(
'goog.base called from a method of one name '
+
'to a method of a different name'
);
}
};
bitjs
.
inherits
=
function
(
childCtor
,
parentCtor
)
{
/** @constructor */
function
tempCtor
()
{};
tempCtor
.
prototype
=
parentCtor
.
prototype
;
childCtor
.
superClass_
=
parentCtor
.
prototype
;
childCtor
.
prototype
=
new
tempCtor
();
childCtor
.
prototype
.
constructor
=
childCtor
;
};
// ===========================================================================
/**
* An unarchive event.
*
* @param {string} type The event type.
* @constructor
*/
bitjs
.
archive
.
UnarchiveEvent
=
function
(
type
)
{
/**
* The event type.
*
* @type {string}
*/
this
.
type
=
type
;
};
/**
* Removes an event listener.
*
* @param {string} Event type.
* @param {EventListener|function} An event listener or handler function.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
removeEventListener
=
function
(
type
,
listener
)
{
if
(
type
in
this
.
listeners_
)
{
var
index
=
this
.
listeners_
[
type
].
indexOf
(
listener
);
if
(
index
!=
-
1
)
{
this
.
listeners_
[
type
].
splice
(
index
,
1
);
}
}
};
/**
* The UnarchiveEvent types.
*/
bitjs
.
archive
.
UnarchiveEvent
.
Type
=
{
START
:
'start'
,
PROGRESS
:
'progress'
,
EXTRACT
:
'extract'
,
FINISH
:
'finish'
,
INFO
:
'info'
,
ERROR
:
'error'
};
/**
* Receive an event and pass it to the listener functions.
*
* @param {bitjs.archive.UnarchiveEvent} e
* @private
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
handleWorkerEvent_
=
function
(
e
)
{
if
((
e
instanceof
bitjs
.
archive
.
UnarchiveEvent
||
e
.
type
)
&&
this
.
listeners_
[
e
.
type
]
instanceof
Array
)
{
this
.
listeners_
[
e
.
type
].
forEach
(
function
(
listener
)
{
listener
(
e
)
});
if
(
e
.
type
==
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
FINISH
)
{
this
.
worker_
.
terminate
();
}
}
else
{
console
.
log
(
e
);
}
};
/**
* Useful for passing info up to the client (for debugging).
*
* @param {string} msg The info message.
*/
bitjs
.
archive
.
UnarchiveInfoEvent
=
function
(
msg
)
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
INFO
);
/**
* The information message.
*
* @type {string}
*/
this
.
msg
=
msg
;
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveInfoEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* An unrecoverable error has occured.
*
* @param {string} msg The error message.
*/
bitjs
.
archive
.
UnarchiveErrorEvent
=
function
(
msg
)
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
ERROR
);
/**
* The information message.
*
* @type {string}
*/
this
.
msg
=
msg
;
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveErrorEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* Start event.
*
* @param {string} msg The info message.
*/
bitjs
.
archive
.
UnarchiveStartEvent
=
function
()
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
START
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveStartEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* Finish event.
*
* @param {string} msg The info message.
*/
bitjs
.
archive
.
UnarchiveFinishEvent
=
function
()
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
FINISH
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveFinishEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* Progress event.
*/
bitjs
.
archive
.
UnarchiveProgressEvent
=
function
(
currentFilename
,
currentFileNumber
,
currentBytesUnarchivedInFile
,
currentBytesUnarchived
,
totalUncompressedBytesInArchive
,
totalFilesInArchive
)
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
PROGRESS
);
this
.
currentFilename
=
currentFilename
;
this
.
currentFileNumber
=
currentFileNumber
;
this
.
currentBytesUnarchivedInFile
=
currentBytesUnarchivedInFile
;
this
.
totalFilesInArchive
=
totalFilesInArchive
;
this
.
currentBytesUnarchived
=
currentBytesUnarchived
;
this
.
totalUncompressedBytesInArchive
=
totalUncompressedBytesInArchive
;
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveProgressEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* All extracted files returned by an Unarchiver will implement
* the following interface:
*
* interface UnarchivedFile {
* string filename
* TypedArray fileData
* }
*
*/
/**
* Extract event.
*/
bitjs
.
archive
.
UnarchiveExtractEvent
=
function
(
unarchivedFile
)
{
bitjs
.
base
(
this
,
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
EXTRACT
);
/**
* @type {UnarchivedFile}
*/
this
.
unarchivedFile
=
unarchivedFile
;
};
bitjs
.
inherits
(
bitjs
.
archive
.
UnarchiveExtractEvent
,
bitjs
.
archive
.
UnarchiveEvent
);
/**
* Base class for all Unarchivers.
*
* @param {ArrayBuffer} arrayBuffer The Array Buffer.
* @param {string} opt_pathToBitJS Optional string for where the BitJS files are located.
* @constructor
*/
bitjs
.
archive
.
Unarchiver
=
function
(
arrayBuffer
,
opt_pathToBitJS
)
{
/**
* The ArrayBuffer object.
* @type {ArrayBuffer}
* @protected
*/
this
.
ab
=
arrayBuffer
;
/**
* The path to the BitJS files.
* @type {string}
* @private
*/
this
.
pathToBitJS_
=
opt_pathToBitJS
||
''
;
/**
* A map from event type to an array of listeners.
* @type {Map.<string, Array>}
*/
this
.
listeners_
=
{};
for
(
var
type
in
bitjs
.
archive
.
UnarchiveEvent
.
Type
)
{
this
.
listeners_
[
bitjs
.
archive
.
UnarchiveEvent
.
Type
[
type
]]
=
[];
}
};
/**
* Starts the unarchive in a separate Web Worker thread and returns immediately.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
start
=
function
()
{
var
me
=
this
;
var
scriptFileName
=
this
.
pathToBitJS_
+
this
.
getScriptFileName
();
if
(
scriptFileName
)
{
this
.
worker_
=
new
Worker
(
scriptFileName
);
this
.
worker_
.
onerror
=
function
(
e
)
{
console
.
log
(
'Worker error: message = '
+
e
.
message
);
throw
e
;
/**
* Private web worker initialized during start().
* @type {Worker}
* @private
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
worker_
=
null
;
/**
* This method must be overridden by the subclass to return the script filename.
* @return {string} The script filename.
* @protected.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
getScriptFileName
=
function
()
{
throw
'Subclasses of AbstractUnarchiver must overload getScriptFileName()'
;
};
this
.
worker_
.
onmessage
=
function
(
e
)
{
if
(
typeof
e
.
data
==
'string'
)
{
// Just log any strings the workers pump our way.
console
.
log
(
e
.
data
);
}
else
{
// Assume that it is an UnarchiveEvent. Some browsers preserve the 'type'
// so that instanceof UnarchiveEvent returns true, but others do not.
me
.
handleWorkerEvent_
(
e
.
data
);
}
/**
* Adds an event listener for UnarchiveEvents.
*
* @param {string} Event type.
* @param {function} An event handler function.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
addEventListener
=
function
(
type
,
listener
)
{
if
(
type
in
this
.
listeners_
)
{
if
(
this
.
listeners_
[
type
].
indexOf
(
listener
)
==
-
1
)
{
this
.
listeners_
[
type
].
push
(
listener
);
}
}
};
this
.
worker_
.
postMessage
({
file
:
this
.
ab
});
}
};
/**
* Removes an event listener.
*
* @param {string} Event type.
* @param {EventListener|function} An event listener or handler function.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
removeEventListener
=
function
(
type
,
listener
)
{
if
(
type
in
this
.
listeners_
)
{
var
index
=
this
.
listeners_
[
type
].
indexOf
(
listener
);
if
(
index
!=
-
1
)
{
this
.
listeners_
[
type
].
splice
(
index
,
1
);
}
}
};
/**
* Terminates the Web Worker for this Unarchiver and returns immediately.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
stop
=
function
()
{
if
(
this
.
worker_
)
{
this
.
worker_
.
terminate
();
}
};
/**
* Receive an event and pass it to the listener functions.
*
* @param {bitjs.archive.UnarchiveEvent} e
* @private
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
handleWorkerEvent_
=
function
(
e
)
{
if
((
e
instanceof
bitjs
.
archive
.
UnarchiveEvent
||
e
.
type
)
&&
this
.
listeners_
[
e
.
type
]
instanceof
Array
)
{
this
.
listeners_
[
e
.
type
].
forEach
(
function
(
listener
)
{
listener
(
e
)
});
if
(
e
.
type
==
bitjs
.
archive
.
UnarchiveEvent
.
Type
.
FINISH
)
{
this
.
worker_
.
terminate
();
}
}
else
{
console
.
log
(
e
);
}
};
/**
* Starts the unarchive in a separate Web Worker thread and returns immediately.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
start
=
function
()
{
var
me
=
this
;
var
scriptFileName
=
this
.
pathToBitJS_
+
this
.
getScriptFileName
();
if
(
scriptFileName
)
{
this
.
worker_
=
new
Worker
(
scriptFileName
);
this
.
worker_
.
onerror
=
function
(
e
)
{
console
.
log
(
'Worker error: message = '
+
e
.
message
);
throw
e
;
};
this
.
worker_
.
onmessage
=
function
(
e
)
{
if
(
typeof
e
.
data
==
'string'
)
{
// Just log any strings the workers pump our way.
console
.
log
(
e
.
data
);
}
else
{
// Assume that it is an UnarchiveEvent. Some browsers preserve the 'type'
// so that instanceof UnarchiveEvent returns true, but others do not.
me
.
handleWorkerEvent_
(
e
.
data
);
}
};
this
.
worker_
.
postMessage
({
file
:
this
.
ab
});
}
};
/**
* Unzipper
* @extends {bitjs.archive.Unarchiver}
* @constructor
*/
bitjs
.
archive
.
Unzipper
=
function
(
arrayBuffer
,
opt_pathToBitJS
)
{
bitjs
.
base
(
this
,
arrayBuffer
,
opt_pathToBitJS
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
Unzipper
,
bitjs
.
archive
.
Unarchiver
);
bitjs
.
archive
.
Unzipper
.
prototype
.
getScriptFileName
=
function
()
{
return
'unzip.js'
};
/**
* Terminates the Web Worker for this Unarchiver and returns immediately.
*/
bitjs
.
archive
.
Unarchiver
.
prototype
.
stop
=
function
()
{
if
(
this
.
worker_
)
{
this
.
worker_
.
terminate
();
}
};
/**
* Unrarrer
* @extends {bitjs.archive.Unarchiver}
* @constructor
*/
bitjs
.
archive
.
Unrarrer
=
function
(
arrayBuffer
,
opt_pathToBitJS
)
{
bitjs
.
base
(
this
,
arrayBuffer
,
opt_pathToBitJS
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
Unrarrer
,
bitjs
.
archive
.
Unarchiver
);
bitjs
.
archive
.
Unrarrer
.
prototype
.
getScriptFileName
=
function
()
{
return
'unrar.js'
};
/**
* Untarrer
* @extends {bitjs.archive.Unarchiver}
* @constructor
*/
bitjs
.
archive
.
Untarrer
=
function
(
arrayBuffer
,
opt_pathToBitJS
)
{
bitjs
.
base
(
this
,
arrayBuffer
,
opt_pathToBitJS
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
Untarrer
,
bitjs
.
archive
.
Unarchiver
);
bitjs
.
archive
.
Untarrer
.
prototype
.
getScriptFileName
=
function
()
{
return
'untar.js'
};
/**
* Unzipper
* @extends {bitjs.archive.Unarchiver}
* @constructor
*/
bitjs
.
archive
.
Unzipper
=
function
(
arrayBuffer
,
opt_pathToBitJS
)
{
bitjs
.
base
(
this
,
arrayBuffer
,
opt_pathToBitJS
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
Unzipper
,
bitjs
.
archive
.
Unarchiver
);
bitjs
.
archive
.
Unzipper
.
prototype
.
getScriptFileName
=
function
()
{
return
'unzip.js'
};
/**
* Unrarrer
* @extends {bitjs.archive.Unarchiver}
* @constructor
*/
bitjs
.
archive
.
Unrarrer
=
function
(
arrayBuffer
,
opt_pathToBitJS
)
{
bitjs
.
base
(
this
,
arrayBuffer
,
opt_pathToBitJS
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
Unrarrer
,
bitjs
.
archive
.
Unarchiver
);
bitjs
.
archive
.
Unrarrer
.
prototype
.
getScriptFileName
=
function
()
{
return
'unrar.js'
};
/**
* Untarrer
* @extends {bitjs.archive.Unarchiver}
* @constructor
*/
bitjs
.
archive
.
Untarrer
=
function
(
arrayBuffer
,
opt_pathToBitJS
)
{
bitjs
.
base
(
this
,
arrayBuffer
,
opt_pathToBitJS
);
};
bitjs
.
inherits
(
bitjs
.
archive
.
Untarrer
,
bitjs
.
archive
.
Unarchiver
);
bitjs
.
archive
.
Untarrer
.
prototype
.
getScriptFileName
=
function
()
{
return
'untar.js'
};
})();
\ No newline at end of file
})();
cps/static/js/io.js
View file @
a159bb0b
...
...
@@ -14,470 +14,469 @@ bitjs.io = bitjs.io || {};
(
function
()
{
// mask for getting the Nth bit (zero-based)
bitjs
.
BIT
=
[
0x01
,
0x02
,
0x04
,
0x08
,
0x10
,
0x20
,
0x40
,
0x80
,
0x100
,
0x200
,
0x400
,
0x800
,
0x1000
,
0x2000
,
0x4000
,
0x8000
];
// mask for getting N number of bits (0-8)
var
BITMASK
=
[
0
,
0x01
,
0x03
,
0x07
,
0x0F
,
0x1F
,
0x3F
,
0x7F
,
0xFF
];
/**
* This bit stream peeks and consumes bits out of a binary stream.
*
* @param {ArrayBuffer} ab An ArrayBuffer object or a Uint8Array.
* @param {boolean} rtl Whether the stream reads bits from the byte starting
* from bit 7 to 0 (true) or bit 0 to 7 (false).
* @param {Number} opt_offset The offset into the ArrayBuffer
* @param {Number} opt_length The length of this BitStream
*/
bitjs
.
io
.
BitStream
=
function
(
ab
,
rtl
,
opt_offset
,
opt_length
)
{
if
(
!
ab
||
!
ab
.
toString
||
ab
.
toString
()
!==
"[object ArrayBuffer]"
)
{
throw
"Error! BitArray constructed with an invalid ArrayBuffer object"
;
}
var
offset
=
opt_offset
||
0
;
var
length
=
opt_length
||
ab
.
byteLength
;
this
.
bytes
=
new
Uint8Array
(
ab
,
offset
,
length
);
this
.
bytePtr
=
0
;
// tracks which byte we are on
this
.
bitPtr
=
0
;
// tracks which bit we are on (can have values 0 through 7)
this
.
peekBits
=
rtl
?
this
.
peekBits_rtl
:
this
.
peekBits_ltr
;
};
/**
* byte0 byte1 byte2 byte3
* 7......0 | 7......0 | 7......0 | 7......0
*
* The bit pointer starts at bit0 of byte0 and moves left until it reaches
* bit7 of byte0, then jumps to bit0 of byte1, etc.
* @param {number} n The number of bits to peek.
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
* @return {number} The peeked bits, as an unsigned number.
*/
bitjs
.
io
.
BitStream
.
prototype
.
peekBits_ltr
=
function
(
n
,
movePointers
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
0
;
}
var
movePointers
=
movePointers
||
false
,
bytePtr
=
this
.
bytePtr
,
bitPtr
=
this
.
bitPtr
,
result
=
0
,
bitsIn
=
0
,
bytes
=
this
.
bytes
;
// keep going until we have no more bits left to peek at
// TODO: Consider putting all bits from bytes we will need into a variable and then
// shifting/masking it to just extract the bits we want.
// This could be considerably faster when reading more than 3 or 4 bits at a time.
while
(
n
>
0
)
{
if
(
bytePtr
>=
bytes
.
length
)
{
throw
"Error! Overflowed the bit stream! n="
+
n
+
", bytePtr="
+
bytePtr
+
", bytes.length="
+
bytes
.
length
+
", bitPtr="
+
bitPtr
;
return
-
1
;
}
var
numBitsLeftInThisByte
=
(
8
-
bitPtr
);
if
(
n
>=
numBitsLeftInThisByte
)
{
var
mask
=
(
BITMASK
[
numBitsLeftInThisByte
]
<<
bitPtr
);
result
|=
(((
bytes
[
bytePtr
]
&
mask
)
>>
bitPtr
)
<<
bitsIn
);
bytePtr
++
;
bitPtr
=
0
;
bitsIn
+=
numBitsLeftInThisByte
;
n
-=
numBitsLeftInThisByte
;
}
else
{
var
mask
=
(
BITMASK
[
n
]
<<
bitPtr
);
result
|=
(((
bytes
[
bytePtr
]
&
mask
)
>>
bitPtr
)
<<
bitsIn
);
bitPtr
+=
n
;
bitsIn
+=
n
;
n
=
0
;
}
}
if
(
movePointers
)
{
this
.
bitPtr
=
bitPtr
;
this
.
bytePtr
=
bytePtr
;
}
return
result
;
};
/**
* byte0 byte1 byte2 byte3
* 7......0 | 7......0 | 7......0 | 7......0
*
* The bit pointer starts at bit7 of byte0 and moves right until it reaches
* bit0 of byte0, then goes to bit7 of byte1, etc.
* @param {number} n The number of bits to peek.
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
* @return {number} The peeked bits, as an unsigned number.
*/
bitjs
.
io
.
BitStream
.
prototype
.
peekBits_rtl
=
function
(
n
,
movePointers
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
0
;
}
var
movePointers
=
movePointers
||
false
,
bytePtr
=
this
.
bytePtr
,
bitPtr
=
this
.
bitPtr
,
result
=
0
,
bytes
=
this
.
bytes
;
// keep going until we have no more bits left to peek at
// TODO: Consider putting all bits from bytes we will need into a variable and then
// shifting/masking it to just extract the bits we want.
// This could be considerably faster when reading more than 3 or 4 bits at a time.
while
(
n
>
0
)
{
if
(
bytePtr
>=
bytes
.
length
)
{
throw
"Error! Overflowed the bit stream! n="
+
n
+
", bytePtr="
+
bytePtr
+
", bytes.length="
+
bytes
.
length
+
", bitPtr="
+
bitPtr
;
return
-
1
;
}
var
numBitsLeftInThisByte
=
(
8
-
bitPtr
);
if
(
n
>=
numBitsLeftInThisByte
)
{
result
<<=
numBitsLeftInThisByte
;
result
|=
(
BITMASK
[
numBitsLeftInThisByte
]
&
bytes
[
bytePtr
]);
bytePtr
++
;
bitPtr
=
0
;
n
-=
numBitsLeftInThisByte
;
}
else
{
result
<<=
n
;
result
|=
((
bytes
[
bytePtr
]
&
(
BITMASK
[
n
]
<<
(
8
-
n
-
bitPtr
)))
>>
(
8
-
n
-
bitPtr
));
bitPtr
+=
n
;
n
=
0
;
}
}
if
(
movePointers
)
{
this
.
bitPtr
=
bitPtr
;
this
.
bytePtr
=
bytePtr
;
}
return
result
;
};
/**
* Some voodoo magic.
*/
bitjs
.
io
.
BitStream
.
prototype
.
getBits
=
function
()
{
return
(((((
this
.
bytes
[
this
.
bytePtr
]
&
0xff
)
<<
16
)
+
((
this
.
bytes
[
this
.
bytePtr
+
1
]
&
0xff
)
<<
8
)
+
((
this
.
bytes
[
this
.
bytePtr
+
2
]
&
0xff
)))
>>>
(
8
-
this
.
bitPtr
))
&
0xffff
);
};
/**
* Reads n bits out of the stream, consuming them (moving the bit pointer).
* @param {number} n The number of bits to read.
* @return {number} The read bits, as an unsigned number.
*/
bitjs
.
io
.
BitStream
.
prototype
.
readBits
=
function
(
n
)
{
return
this
.
peekBits
(
n
,
true
);
};
/**
* This returns n bytes as a sub-array, advancing the pointer if movePointers
* is true. Only use this for uncompressed blocks as this throws away remaining
* bits in the current byte.
* @param {number} n The number of bytes to peek.
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
* @return {Uint8Array} The subarray.
*/
bitjs
.
io
.
BitStream
.
prototype
.
peekBytes
=
function
(
n
,
movePointers
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
0
;
}
// from http://tools.ietf.org/html/rfc1951#page-11
// "Any bits of input up to the next byte boundary are ignored."
while
(
this
.
bitPtr
!=
0
)
{
this
.
readBits
(
1
);
}
var
movePointers
=
movePointers
||
false
;
var
bytePtr
=
this
.
bytePtr
,
bitPtr
=
this
.
bitPtr
;
var
result
=
this
.
bytes
.
subarray
(
bytePtr
,
bytePtr
+
n
);
if
(
movePointers
)
{
this
.
bytePtr
+=
n
;
}
return
result
;
};
/**
* @param {number} n The number of bytes to read.
* @return {Uint8Array} The subarray.
*/
bitjs
.
io
.
BitStream
.
prototype
.
readBytes
=
function
(
n
)
{
return
this
.
peekBytes
(
n
,
true
);
};
/**
* This object allows you to peek and consume bytes as numbers and strings
* out of an ArrayBuffer. In this buffer, everything must be byte-aligned.
*
* @param {ArrayBuffer} ab The ArrayBuffer object.
* @param {number=} opt_offset The offset into the ArrayBuffer
* @param {number=} opt_length The length of this BitStream
* @constructor
*/
bitjs
.
io
.
ByteStream
=
function
(
ab
,
opt_offset
,
opt_length
)
{
var
offset
=
opt_offset
||
0
;
var
length
=
opt_length
||
ab
.
byteLength
;
this
.
bytes
=
new
Uint8Array
(
ab
,
offset
,
length
);
this
.
ptr
=
0
;
};
/**
* Peeks at the next n bytes as an unsigned number but does not advance the
* pointer
* TODO: This apparently cannot read more than 4 bytes as a number?
* @param {number} n The number of bytes to peek at.
* @return {number} The n bytes interpreted as an unsigned number.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
peekNumber
=
function
(
n
)
{
// TODO: return error if n would go past the end of the stream?
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
return
-
1
;
var
result
=
0
;
// read from last byte to first byte and roll them in
var
curByte
=
this
.
ptr
+
n
-
1
;
while
(
curByte
>=
this
.
ptr
)
{
result
<<=
8
;
result
|=
this
.
bytes
[
curByte
];
--
curByte
;
}
return
result
;
};
/**
* Returns the next n bytes as an unsigned number (or -1 on error)
* and advances the stream pointer n bytes.
* @param {number} n The number of bytes to read.
* @return {number} The n bytes interpreted as an unsigned number.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
readNumber
=
function
(
n
)
{
var
num
=
this
.
peekNumber
(
n
);
this
.
ptr
+=
n
;
return
num
;
};
/**
* Returns the next n bytes as a signed number but does not advance the
* pointer.
* @param {number} n The number of bytes to read.
* @return {number} The bytes interpreted as a signed number.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
peekSignedNumber
=
function
(
n
)
{
var
num
=
this
.
peekNumber
(
n
);
var
HALF
=
Math
.
pow
(
2
,
(
n
*
8
)
-
1
);
var
FULL
=
HALF
*
2
;
if
(
num
>=
HALF
)
num
-=
FULL
;
return
num
;
};
/**
* Returns the next n bytes as a signed number and advances the stream pointer.
* @param {number} n The number of bytes to read.
* @return {number} The bytes interpreted as a signed number.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
readSignedNumber
=
function
(
n
)
{
var
num
=
this
.
peekSignedNumber
(
n
);
this
.
ptr
+=
n
;
return
num
;
};
/**
* This returns n bytes as a sub-array, advancing the pointer if movePointers
* is true.
* @param {number} n The number of bytes to read.
* @param {boolean} movePointers Whether to move the pointers.
* @return {Uint8Array} The subarray.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
peekBytes
=
function
(
n
,
movePointers
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
null
;
}
var
result
=
this
.
bytes
.
subarray
(
this
.
ptr
,
this
.
ptr
+
n
);
if
(
movePointers
)
{
this
.
ptr
+=
n
;
}
return
result
;
};
/**
* Reads the next n bytes as a sub-array.
* @param {number} n The number of bytes to read.
* @return {Uint8Array} The subarray.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
readBytes
=
function
(
n
)
{
return
this
.
peekBytes
(
n
,
true
);
};
/**
* Peeks at the next n bytes as a string but does not advance the pointer.
* @param {number} n The number of bytes to peek at.
* @return {string} The next n bytes as a string.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
peekString
=
function
(
n
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
""
;
}
var
result
=
""
;
for
(
var
p
=
this
.
ptr
,
end
=
this
.
ptr
+
n
;
p
<
end
;
++
p
)
{
result
+=
String
.
fromCharCode
(
this
.
bytes
[
p
]);
}
return
result
;
};
/**
* Returns the next n bytes as an ASCII string and advances the stream pointer
* n bytes.
* @param {number} n The number of bytes to read.
* @return {string} The next n bytes as a string.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
readString
=
function
(
n
)
{
var
strToReturn
=
this
.
peekString
(
n
);
this
.
ptr
+=
n
;
return
strToReturn
;
};
/**
* A write-only Byte buffer which uses a Uint8 Typed Array as a backing store.
* @param {number} numBytes The number of bytes to allocate.
* @constructor
*/
bitjs
.
io
.
ByteBuffer
=
function
(
numBytes
)
{
if
(
typeof
numBytes
!=
typeof
1
||
numBytes
<=
0
)
{
throw
"Error! ByteBuffer initialized with '"
+
numBytes
+
"'"
;
}
this
.
data
=
new
Uint8Array
(
numBytes
);
this
.
ptr
=
0
;
};
/**
* @param {number} b The byte to insert.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
insertByte
=
function
(
b
)
{
// TODO: throw if byte is invalid?
this
.
data
[
this
.
ptr
++
]
=
b
;
};
/**
* @param {Array.<number>|Uint8Array|Int8Array} bytes The bytes to insert.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
insertBytes
=
function
(
bytes
)
{
// TODO: throw if bytes is invalid?
this
.
data
.
set
(
bytes
,
this
.
ptr
);
this
.
ptr
+=
bytes
.
length
;
};
/**
* Writes an unsigned number into the next n bytes. If the number is too large
* to fit into n bytes or is negative, an error is thrown.
* @param {number} num The unsigned number to write.
* @param {number} numBytes The number of bytes to write the number into.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
writeNumber
=
function
(
num
,
numBytes
)
{
if
(
numBytes
<
1
)
{
throw
'Trying to write into too few bytes: '
+
numBytes
;
}
if
(
num
<
0
)
{
throw
'Trying to write a negative number ('
+
num
+
') as an unsigned number to an ArrayBuffer'
;
}
if
(
num
>
(
Math
.
pow
(
2
,
numBytes
*
8
)
-
1
))
{
throw
'Trying to write '
+
num
+
' into only '
+
numBytes
+
' bytes'
;
}
// Roll 8-bits at a time into an array of bytes.
var
bytes
=
[];
while
(
numBytes
--
>
0
)
{
var
eightBits
=
num
&
255
;
bytes
.
push
(
eightBits
);
num
>>=
8
;
}
this
.
insertBytes
(
bytes
);
};
/**
* Writes a signed number into the next n bytes. If the number is too large
* to fit into n bytes, an error is thrown.
* @param {number} num The signed number to write.
* @param {number} numBytes The number of bytes to write the number into.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
writeSignedNumber
=
function
(
num
,
numBytes
)
{
if
(
numBytes
<
1
)
{
throw
'Trying to write into too few bytes: '
+
numBytes
;
}
var
HALF
=
Math
.
pow
(
2
,
(
numBytes
*
8
)
-
1
);
if
(
num
>=
HALF
||
num
<
-
HALF
)
{
throw
'Trying to write '
+
num
+
' into only '
+
numBytes
+
' bytes'
;
}
// Roll 8-bits at a time into an array of bytes.
var
bytes
=
[];
while
(
numBytes
--
>
0
)
{
var
eightBits
=
num
&
255
;
bytes
.
push
(
eightBits
);
num
>>=
8
;
}
this
.
insertBytes
(
bytes
);
};
/**
* @param {string} str The ASCII string to write.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
writeASCIIString
=
function
(
str
)
{
for
(
var
i
=
0
;
i
<
str
.
length
;
++
i
)
{
var
curByte
=
str
.
charCodeAt
(
i
);
if
(
curByte
<
0
||
curByte
>
255
)
{
throw
'Trying to write a non-ASCII string!'
;
}
this
.
insertByte
(
curByte
);
}
};
// mask for getting the Nth bit (zero-based)
bitjs
.
BIT
=
[
0x01
,
0x02
,
0x04
,
0x08
,
0x10
,
0x20
,
0x40
,
0x80
,
0x100
,
0x200
,
0x400
,
0x800
,
0x1000
,
0x2000
,
0x4000
,
0x8000
];
// mask for getting N number of bits (0-8)
var
BITMASK
=
[
0
,
0x01
,
0x03
,
0x07
,
0x0F
,
0x1F
,
0x3F
,
0x7F
,
0xFF
];
/**
* This bit stream peeks and consumes bits out of a binary stream.
*
* @param {ArrayBuffer} ab An ArrayBuffer object or a Uint8Array.
* @param {boolean} rtl Whether the stream reads bits from the byte starting
* from bit 7 to 0 (true) or bit 0 to 7 (false).
* @param {Number} opt_offset The offset into the ArrayBuffer
* @param {Number} opt_length The length of this BitStream
*/
bitjs
.
io
.
BitStream
=
function
(
ab
,
rtl
,
opt_offset
,
opt_length
)
{
if
(
!
ab
||
!
ab
.
toString
||
ab
.
toString
()
!==
"[object ArrayBuffer]"
)
{
throw
"Error! BitArray constructed with an invalid ArrayBuffer object"
;
}
var
offset
=
opt_offset
||
0
;
var
length
=
opt_length
||
ab
.
byteLength
;
this
.
bytes
=
new
Uint8Array
(
ab
,
offset
,
length
);
this
.
bytePtr
=
0
;
// tracks which byte we are on
this
.
bitPtr
=
0
;
// tracks which bit we are on (can have values 0 through 7)
this
.
peekBits
=
rtl
?
this
.
peekBits_rtl
:
this
.
peekBits_ltr
;
};
/**
* byte0 byte1 byte2 byte3
* 7......0 | 7......0 | 7......0 | 7......0
*
* The bit pointer starts at bit0 of byte0 and moves left until it reaches
* bit7 of byte0, then jumps to bit0 of byte1, etc.
* @param {number} n The number of bits to peek.
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
* @return {number} The peeked bits, as an unsigned number.
*/
bitjs
.
io
.
BitStream
.
prototype
.
peekBits_ltr
=
function
(
n
,
movePointers
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
0
;
}
var
movePointers
=
movePointers
||
false
,
bytePtr
=
this
.
bytePtr
,
bitPtr
=
this
.
bitPtr
,
result
=
0
,
bitsIn
=
0
,
bytes
=
this
.
bytes
;
// keep going until we have no more bits left to peek at
// TODO: Consider putting all bits from bytes we will need into a variable and then
// shifting/masking it to just extract the bits we want.
// This could be considerably faster when reading more than 3 or 4 bits at a time.
while
(
n
>
0
)
{
if
(
bytePtr
>=
bytes
.
length
)
{
throw
"Error! Overflowed the bit stream! n="
+
n
+
", bytePtr="
+
bytePtr
+
", bytes.length="
+
bytes
.
length
+
", bitPtr="
+
bitPtr
;
return
-
1
;
}
var
numBitsLeftInThisByte
=
(
8
-
bitPtr
);
if
(
n
>=
numBitsLeftInThisByte
)
{
var
mask
=
(
BITMASK
[
numBitsLeftInThisByte
]
<<
bitPtr
);
result
|=
(((
bytes
[
bytePtr
]
&
mask
)
>>
bitPtr
)
<<
bitsIn
);
bytePtr
++
;
bitPtr
=
0
;
bitsIn
+=
numBitsLeftInThisByte
;
n
-=
numBitsLeftInThisByte
;
}
else
{
var
mask
=
(
BITMASK
[
n
]
<<
bitPtr
);
result
|=
(((
bytes
[
bytePtr
]
&
mask
)
>>
bitPtr
)
<<
bitsIn
);
bitPtr
+=
n
;
bitsIn
+=
n
;
n
=
0
;
}
}
if
(
movePointers
)
{
this
.
bitPtr
=
bitPtr
;
this
.
bytePtr
=
bytePtr
;
}
return
result
;
};
/**
* byte0 byte1 byte2 byte3
* 7......0 | 7......0 | 7......0 | 7......0
*
* The bit pointer starts at bit7 of byte0 and moves right until it reaches
* bit0 of byte0, then goes to bit7 of byte1, etc.
* @param {number} n The number of bits to peek.
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
* @return {number} The peeked bits, as an unsigned number.
*/
bitjs
.
io
.
BitStream
.
prototype
.
peekBits_rtl
=
function
(
n
,
movePointers
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
0
;
}
var
movePointers
=
movePointers
||
false
,
bytePtr
=
this
.
bytePtr
,
bitPtr
=
this
.
bitPtr
,
result
=
0
,
bytes
=
this
.
bytes
;
// keep going until we have no more bits left to peek at
// TODO: Consider putting all bits from bytes we will need into a variable and then
// shifting/masking it to just extract the bits we want.
// This could be considerably faster when reading more than 3 or 4 bits at a time.
while
(
n
>
0
)
{
if
(
bytePtr
>=
bytes
.
length
)
{
throw
"Error! Overflowed the bit stream! n="
+
n
+
", bytePtr="
+
bytePtr
+
", bytes.length="
+
bytes
.
length
+
", bitPtr="
+
bitPtr
;
return
-
1
;
}
var
numBitsLeftInThisByte
=
(
8
-
bitPtr
);
if
(
n
>=
numBitsLeftInThisByte
)
{
result
<<=
numBitsLeftInThisByte
;
result
|=
(
BITMASK
[
numBitsLeftInThisByte
]
&
bytes
[
bytePtr
]);
bytePtr
++
;
bitPtr
=
0
;
n
-=
numBitsLeftInThisByte
;
}
else
{
result
<<=
n
;
result
|=
((
bytes
[
bytePtr
]
&
(
BITMASK
[
n
]
<<
(
8
-
n
-
bitPtr
)))
>>
(
8
-
n
-
bitPtr
));
bitPtr
+=
n
;
n
=
0
;
}
}
if
(
movePointers
)
{
this
.
bitPtr
=
bitPtr
;
this
.
bytePtr
=
bytePtr
;
}
return
result
;
};
/**
* Some voodoo magic.
*/
bitjs
.
io
.
BitStream
.
prototype
.
getBits
=
function
()
{
return
(((((
this
.
bytes
[
this
.
bytePtr
]
&
0xff
)
<<
16
)
+
((
this
.
bytes
[
this
.
bytePtr
+
1
]
&
0xff
)
<<
8
)
+
((
this
.
bytes
[
this
.
bytePtr
+
2
]
&
0xff
)))
>>>
(
8
-
this
.
bitPtr
))
&
0xffff
);
};
/**
* Reads n bits out of the stream, consuming them (moving the bit pointer).
* @param {number} n The number of bits to read.
* @return {number} The read bits, as an unsigned number.
*/
bitjs
.
io
.
BitStream
.
prototype
.
readBits
=
function
(
n
)
{
return
this
.
peekBits
(
n
,
true
);
};
/**
* This returns n bytes as a sub-array, advancing the pointer if movePointers
* is true. Only use this for uncompressed blocks as this throws away remaining
* bits in the current byte.
* @param {number} n The number of bytes to peek.
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
* @return {Uint8Array} The subarray.
*/
bitjs
.
io
.
BitStream
.
prototype
.
peekBytes
=
function
(
n
,
movePointers
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
0
;
}
// from http://tools.ietf.org/html/rfc1951#page-11
// "Any bits of input up to the next byte boundary are ignored."
while
(
this
.
bitPtr
!=
0
)
{
this
.
readBits
(
1
);
}
var
movePointers
=
movePointers
||
false
;
var
bytePtr
=
this
.
bytePtr
,
bitPtr
=
this
.
bitPtr
;
var
result
=
this
.
bytes
.
subarray
(
bytePtr
,
bytePtr
+
n
);
if
(
movePointers
)
{
this
.
bytePtr
+=
n
;
}
return
result
;
};
/**
* @param {number} n The number of bytes to read.
* @return {Uint8Array} The subarray.
*/
bitjs
.
io
.
BitStream
.
prototype
.
readBytes
=
function
(
n
)
{
return
this
.
peekBytes
(
n
,
true
);
};
/**
* This object allows you to peek and consume bytes as numbers and strings
* out of an ArrayBuffer. In this buffer, everything must be byte-aligned.
*
* @param {ArrayBuffer} ab The ArrayBuffer object.
* @param {number=} opt_offset The offset into the ArrayBuffer
* @param {number=} opt_length The length of this BitStream
* @constructor
*/
bitjs
.
io
.
ByteStream
=
function
(
ab
,
opt_offset
,
opt_length
)
{
var
offset
=
opt_offset
||
0
;
var
length
=
opt_length
||
ab
.
byteLength
;
this
.
bytes
=
new
Uint8Array
(
ab
,
offset
,
length
);
this
.
ptr
=
0
;
};
/**
* Peeks at the next n bytes as an unsigned number but does not advance the
* pointer
* TODO: This apparently cannot read more than 4 bytes as a number?
* @param {number} n The number of bytes to peek at.
* @return {number} The n bytes interpreted as an unsigned number.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
peekNumber
=
function
(
n
)
{
// TODO: return error if n would go past the end of the stream?
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
return
-
1
;
var
result
=
0
;
// read from last byte to first byte and roll them in
var
curByte
=
this
.
ptr
+
n
-
1
;
while
(
curByte
>=
this
.
ptr
)
{
result
<<=
8
;
result
|=
this
.
bytes
[
curByte
];
--
curByte
;
}
return
result
;
};
/**
* Returns the next n bytes as an unsigned number (or -1 on error)
* and advances the stream pointer n bytes.
* @param {number} n The number of bytes to read.
* @return {number} The n bytes interpreted as an unsigned number.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
readNumber
=
function
(
n
)
{
var
num
=
this
.
peekNumber
(
n
);
this
.
ptr
+=
n
;
return
num
;
};
/**
* Returns the next n bytes as a signed number but does not advance the
* pointer.
* @param {number} n The number of bytes to read.
* @return {number} The bytes interpreted as a signed number.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
peekSignedNumber
=
function
(
n
)
{
var
num
=
this
.
peekNumber
(
n
);
var
HALF
=
Math
.
pow
(
2
,
(
n
*
8
)
-
1
);
var
FULL
=
HALF
*
2
;
if
(
num
>=
HALF
)
num
-=
FULL
;
return
num
;
};
/**
* Returns the next n bytes as a signed number and advances the stream pointer.
* @param {number} n The number of bytes to read.
* @return {number} The bytes interpreted as a signed number.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
readSignedNumber
=
function
(
n
)
{
var
num
=
this
.
peekSignedNumber
(
n
);
this
.
ptr
+=
n
;
return
num
;
};
/**
* This returns n bytes as a sub-array, advancing the pointer if movePointers
* is true.
* @param {number} n The number of bytes to read.
* @param {boolean} movePointers Whether to move the pointers.
* @return {Uint8Array} The subarray.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
peekBytes
=
function
(
n
,
movePointers
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
null
;
}
var
result
=
this
.
bytes
.
subarray
(
this
.
ptr
,
this
.
ptr
+
n
);
if
(
movePointers
)
{
this
.
ptr
+=
n
;
}
return
result
;
};
/**
* Reads the next n bytes as a sub-array.
* @param {number} n The number of bytes to read.
* @return {Uint8Array} The subarray.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
readBytes
=
function
(
n
)
{
return
this
.
peekBytes
(
n
,
true
);
};
/**
* Peeks at the next n bytes as a string but does not advance the pointer.
* @param {number} n The number of bytes to peek at.
* @return {string} The next n bytes as a string.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
peekString
=
function
(
n
)
{
if
(
n
<=
0
||
typeof
n
!=
typeof
1
)
{
return
""
;
}
var
result
=
""
;
for
(
var
p
=
this
.
ptr
,
end
=
this
.
ptr
+
n
;
p
<
end
;
++
p
)
{
result
+=
String
.
fromCharCode
(
this
.
bytes
[
p
]);
}
return
result
;
};
/**
* Returns the next n bytes as an ASCII string and advances the stream pointer
* n bytes.
* @param {number} n The number of bytes to read.
* @return {string} The next n bytes as a string.
*/
bitjs
.
io
.
ByteStream
.
prototype
.
readString
=
function
(
n
)
{
var
strToReturn
=
this
.
peekString
(
n
);
this
.
ptr
+=
n
;
return
strToReturn
;
};
/**
* A write-only Byte buffer which uses a Uint8 Typed Array as a backing store.
* @param {number} numBytes The number of bytes to allocate.
* @constructor
*/
bitjs
.
io
.
ByteBuffer
=
function
(
numBytes
)
{
if
(
typeof
numBytes
!=
typeof
1
||
numBytes
<=
0
)
{
throw
"Error! ByteBuffer initialized with '"
+
numBytes
+
"'"
;
}
this
.
data
=
new
Uint8Array
(
numBytes
);
this
.
ptr
=
0
;
};
/**
* @param {number} b The byte to insert.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
insertByte
=
function
(
b
)
{
// TODO: throw if byte is invalid?
this
.
data
[
this
.
ptr
++
]
=
b
;
};
/**
* @param {Array.<number>|Uint8Array|Int8Array} bytes The bytes to insert.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
insertBytes
=
function
(
bytes
)
{
// TODO: throw if bytes is invalid?
this
.
data
.
set
(
bytes
,
this
.
ptr
);
this
.
ptr
+=
bytes
.
length
;
};
/**
* Writes an unsigned number into the next n bytes. If the number is too large
* to fit into n bytes or is negative, an error is thrown.
* @param {number} num The unsigned number to write.
* @param {number} numBytes The number of bytes to write the number into.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
writeNumber
=
function
(
num
,
numBytes
)
{
if
(
numBytes
<
1
)
{
throw
'Trying to write into too few bytes: '
+
numBytes
;
}
if
(
num
<
0
)
{
throw
'Trying to write a negative number ('
+
num
+
') as an unsigned number to an ArrayBuffer'
;
}
if
(
num
>
(
Math
.
pow
(
2
,
numBytes
*
8
)
-
1
))
{
throw
'Trying to write '
+
num
+
' into only '
+
numBytes
+
' bytes'
;
}
// Roll 8-bits at a time into an array of bytes.
var
bytes
=
[];
while
(
numBytes
--
>
0
)
{
var
eightBits
=
num
&
255
;
bytes
.
push
(
eightBits
);
num
>>=
8
;
}
this
.
insertBytes
(
bytes
);
};
/**
* Writes a signed number into the next n bytes. If the number is too large
* to fit into n bytes, an error is thrown.
* @param {number} num The signed number to write.
* @param {number} numBytes The number of bytes to write the number into.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
writeSignedNumber
=
function
(
num
,
numBytes
)
{
if
(
numBytes
<
1
)
{
throw
'Trying to write into too few bytes: '
+
numBytes
;
}
var
HALF
=
Math
.
pow
(
2
,
(
numBytes
*
8
)
-
1
);
if
(
num
>=
HALF
||
num
<
-
HALF
)
{
throw
'Trying to write '
+
num
+
' into only '
+
numBytes
+
' bytes'
;
}
// Roll 8-bits at a time into an array of bytes.
var
bytes
=
[];
while
(
numBytes
--
>
0
)
{
var
eightBits
=
num
&
255
;
bytes
.
push
(
eightBits
);
num
>>=
8
;
}
this
.
insertBytes
(
bytes
);
};
/**
* @param {string} str The ASCII string to write.
*/
bitjs
.
io
.
ByteBuffer
.
prototype
.
writeASCIIString
=
function
(
str
)
{
for
(
var
i
=
0
;
i
<
str
.
length
;
++
i
)
{
var
curByte
=
str
.
charCodeAt
(
i
);
if
(
curByte
<
0
||
curByte
>
255
)
{
throw
'Trying to write a non-ASCII string!'
;
}
this
.
insertByte
(
curByte
);
}
};
})();
cps/static/js/unzip.js
View file @
a159bb0b
...
...
@@ -24,19 +24,19 @@ var totalFilesInArchive = 0;
// Helper functions.
var
info
=
function
(
str
)
{
postMessage
(
new
bitjs
.
archive
.
UnarchiveInfoEvent
(
str
));
postMessage
(
new
bitjs
.
archive
.
UnarchiveInfoEvent
(
str
));
};
var
err
=
function
(
str
)
{
postMessage
(
new
bitjs
.
archive
.
UnarchiveErrorEvent
(
str
));
postMessage
(
new
bitjs
.
archive
.
UnarchiveErrorEvent
(
str
));
};
var
postProgress
=
function
()
{
postMessage
(
new
bitjs
.
archive
.
UnarchiveProgressEvent
(
currentFilename
,
currentFileNumber
,
currentBytesUnarchivedInFile
,
currentBytesUnarchived
,
totalUncompressedBytesInArchive
,
totalFilesInArchive
));
postMessage
(
new
bitjs
.
archive
.
UnarchiveProgressEvent
(
currentFilename
,
currentFileNumber
,
currentBytesUnarchivedInFile
,
currentBytesUnarchived
,
totalUncompressedBytesInArchive
,
totalFilesInArchive
));
};
var
zLocalFileHeaderSignature
=
0x04034b50
;
...
...
@@ -48,82 +48,82 @@ var zEndOfCentralDirLocatorSignature = 0x07064b50;
// takes a ByteStream and parses out the local file information
var
ZipLocalFile
=
function
(
bstream
)
{
if
(
typeof
bstream
!=
typeof
{}
||
!
bstream
.
readNumber
||
typeof
bstream
.
readNumber
!=
typeof
function
(){})
{
return
null
;
}
bstream
.
readNumber
(
4
);
// swallow signature
this
.
version
=
bstream
.
readNumber
(
2
);
this
.
generalPurpose
=
bstream
.
readNumber
(
2
);
this
.
compressionMethod
=
bstream
.
readNumber
(
2
);
this
.
lastModFileTime
=
bstream
.
readNumber
(
2
);
this
.
lastModFileDate
=
bstream
.
readNumber
(
2
);
this
.
crc32
=
bstream
.
readNumber
(
4
);
this
.
compressedSize
=
bstream
.
readNumber
(
4
);
this
.
uncompressedSize
=
bstream
.
readNumber
(
4
);
this
.
fileNameLength
=
bstream
.
readNumber
(
2
);
this
.
extraFieldLength
=
bstream
.
readNumber
(
2
);
this
.
filename
=
null
;
if
(
this
.
fileNameLength
>
0
)
{
this
.
filename
=
bstream
.
readString
(
this
.
fileNameLength
);
}
info
(
"Zip Local File Header:"
);
info
(
" version="
+
this
.
version
);
info
(
" general purpose="
+
this
.
generalPurpose
);
info
(
" compression method="
+
this
.
compressionMethod
);
info
(
" last mod file time="
+
this
.
lastModFileTime
);
info
(
" last mod file date="
+
this
.
lastModFileDate
);
info
(
" crc32="
+
this
.
crc32
);
info
(
" compressed size="
+
this
.
compressedSize
);
info
(
" uncompressed size="
+
this
.
uncompressedSize
);
info
(
" file name length="
+
this
.
fileNameLength
);
info
(
" extra field length="
+
this
.
extraFieldLength
);
info
(
" filename = '"
+
this
.
filename
+
"'"
);
this
.
extraField
=
null
;
if
(
this
.
extraFieldLength
>
0
)
{
this
.
extraField
=
bstream
.
readString
(
this
.
extraFieldLength
);
info
(
" extra field="
+
this
.
extraField
);
}
// read in the compressed data
this
.
fileData
=
null
;
if
(
this
.
compressedSize
>
0
)
{
this
.
fileData
=
new
Uint8Array
(
bstream
.
bytes
.
buffer
,
bstream
.
ptr
,
this
.
compressedSize
);
bstream
.
ptr
+=
this
.
compressedSize
;
}
// TODO: deal with data descriptor if present (we currently assume no data descriptor!)
// "This descriptor exists only if bit 3 of the general purpose bit flag is set"
// But how do you figure out how big the file data is if you don't know the compressedSize
// from the header?!?
if
((
this
.
generalPurpose
&
bitjs
.
BIT
[
3
])
!=
0
)
{
this
.
crc32
=
bstream
.
readNumber
(
4
);
this
.
compressedSize
=
bstream
.
readNumber
(
4
);
this
.
uncompressedSize
=
bstream
.
readNumber
(
4
);
}
if
(
typeof
bstream
!=
typeof
{}
||
!
bstream
.
readNumber
||
typeof
bstream
.
readNumber
!=
typeof
function
(){})
{
return
null
;
}
bstream
.
readNumber
(
4
);
// swallow signature
this
.
version
=
bstream
.
readNumber
(
2
);
this
.
generalPurpose
=
bstream
.
readNumber
(
2
);
this
.
compressionMethod
=
bstream
.
readNumber
(
2
);
this
.
lastModFileTime
=
bstream
.
readNumber
(
2
);
this
.
lastModFileDate
=
bstream
.
readNumber
(
2
);
this
.
crc32
=
bstream
.
readNumber
(
4
);
this
.
compressedSize
=
bstream
.
readNumber
(
4
);
this
.
uncompressedSize
=
bstream
.
readNumber
(
4
);
this
.
fileNameLength
=
bstream
.
readNumber
(
2
);
this
.
extraFieldLength
=
bstream
.
readNumber
(
2
);
this
.
filename
=
null
;
if
(
this
.
fileNameLength
>
0
)
{
this
.
filename
=
bstream
.
readString
(
this
.
fileNameLength
);
}
info
(
"Zip Local File Header:"
);
info
(
" version="
+
this
.
version
);
info
(
" general purpose="
+
this
.
generalPurpose
);
info
(
" compression method="
+
this
.
compressionMethod
);
info
(
" last mod file time="
+
this
.
lastModFileTime
);
info
(
" last mod file date="
+
this
.
lastModFileDate
);
info
(
" crc32="
+
this
.
crc32
);
info
(
" compressed size="
+
this
.
compressedSize
);
info
(
" uncompressed size="
+
this
.
uncompressedSize
);
info
(
" file name length="
+
this
.
fileNameLength
);
info
(
" extra field length="
+
this
.
extraFieldLength
);
info
(
" filename = '"
+
this
.
filename
+
"'"
);
this
.
extraField
=
null
;
if
(
this
.
extraFieldLength
>
0
)
{
this
.
extraField
=
bstream
.
readString
(
this
.
extraFieldLength
);
info
(
" extra field="
+
this
.
extraField
);
}
// read in the compressed data
this
.
fileData
=
null
;
if
(
this
.
compressedSize
>
0
)
{
this
.
fileData
=
new
Uint8Array
(
bstream
.
bytes
.
buffer
,
bstream
.
ptr
,
this
.
compressedSize
);
bstream
.
ptr
+=
this
.
compressedSize
;
}
// TODO: deal with data descriptor if present (we currently assume no data descriptor!)
// "This descriptor exists only if bit 3 of the general purpose bit flag is set"
// But how do you figure out how big the file data is if you don't know the compressedSize
// from the header?!?
if
((
this
.
generalPurpose
&
bitjs
.
BIT
[
3
])
!=
0
)
{
this
.
crc32
=
bstream
.
readNumber
(
4
);
this
.
compressedSize
=
bstream
.
readNumber
(
4
);
this
.
uncompressedSize
=
bstream
.
readNumber
(
4
);
}
};
// determine what kind of compressed data we have and decompress
ZipLocalFile
.
prototype
.
unzip
=
function
()
{
// Zip Version 1.0, no compression (store only)
if
(
this
.
compressionMethod
==
0
)
{
info
(
"ZIP v"
+
this
.
version
+
", store only: "
+
this
.
filename
+
" ("
+
this
.
compressedSize
+
" bytes)"
);
currentBytesUnarchivedInFile
=
this
.
compressedSize
;
currentBytesUnarchived
+=
this
.
compressedSize
;
}
// version == 20, compression method == 8 (DEFLATE)
else
if
(
this
.
compressionMethod
==
8
)
{
info
(
"ZIP v2.0, DEFLATE: "
+
this
.
filename
+
" ("
+
this
.
compressedSize
+
" bytes)"
);
this
.
fileData
=
inflate
(
this
.
fileData
,
this
.
uncompressedSize
);
}
else
{
err
(
"UNSUPPORTED VERSION/FORMAT: ZIP v"
+
this
.
version
+
", compression method="
+
this
.
compressionMethod
+
": "
+
this
.
filename
+
" ("
+
this
.
compressedSize
+
" bytes)"
);
this
.
fileData
=
null
;
}
// Zip Version 1.0, no compression (store only)
if
(
this
.
compressionMethod
==
0
)
{
info
(
"ZIP v"
+
this
.
version
+
", store only: "
+
this
.
filename
+
" ("
+
this
.
compressedSize
+
" bytes)"
);
currentBytesUnarchivedInFile
=
this
.
compressedSize
;
currentBytesUnarchived
+=
this
.
compressedSize
;
}
// version == 20, compression method == 8 (DEFLATE)
else
if
(
this
.
compressionMethod
==
8
)
{
info
(
"ZIP v2.0, DEFLATE: "
+
this
.
filename
+
" ("
+
this
.
compressedSize
+
" bytes)"
);
this
.
fileData
=
inflate
(
this
.
fileData
,
this
.
uncompressedSize
);
}
else
{
err
(
"UNSUPPORTED VERSION/FORMAT: ZIP v"
+
this
.
version
+
", compression method="
+
this
.
compressionMethod
+
": "
+
this
.
filename
+
" ("
+
this
.
compressedSize
+
" bytes)"
);
this
.
fileData
=
null
;
}
};
...
...
@@ -131,112 +131,112 @@ ZipLocalFile.prototype.unzip = function() {
// returns null on error
// returns an array of DecompressedFile objects on success
var
unzip
=
function
(
arrayBuffer
)
{
postMessage
(
new
bitjs
.
archive
.
UnarchiveStartEvent
());
currentFilename
=
""
;
currentFileNumber
=
0
;
currentBytesUnarchivedInFile
=
0
;
currentBytesUnarchived
=
0
;
totalUncompressedBytesInArchive
=
0
;
totalFilesInArchive
=
0
;
currentBytesUnarchived
=
0
;
var
bstream
=
new
bitjs
.
io
.
ByteStream
(
arrayBuffer
);
// detect local file header signature or return null
if
(
bstream
.
peekNumber
(
4
)
==
zLocalFileHeaderSignature
)
{
var
localFiles
=
[];
// loop until we don't see any more local files
while
(
bstream
.
peekNumber
(
4
)
==
zLocalFileHeaderSignature
)
{
var
oneLocalFile
=
new
ZipLocalFile
(
bstream
);
// this should strip out directories/folders
if
(
oneLocalFile
&&
oneLocalFile
.
uncompressedSize
>
0
&&
oneLocalFile
.
fileData
)
{
localFiles
.
push
(
oneLocalFile
);
totalUncompressedBytesInArchive
+=
oneLocalFile
.
uncompressedSize
;
}
}
totalFilesInArchive
=
localFiles
.
length
;
// got all local files, now sort them
localFiles
.
sort
(
function
(
a
,
b
)
{
var
aname
=
a
.
filename
.
toLowerCase
();
var
bname
=
b
.
filename
.
toLowerCase
();
return
aname
>
bname
?
1
:
-
1
;
});
// archive extra data record
if
(
bstream
.
peekNumber
(
4
)
==
zArchiveExtraDataSignature
)
{
info
(
" Found an Archive Extra Data Signature"
);
// skipping this record for now
bstream
.
readNumber
(
4
);
var
archiveExtraFieldLength
=
bstream
.
readNumber
(
4
);
bstream
.
readString
(
archiveExtraFieldLength
);
}
// central directory structure
// TODO: handle the rest of the structures (Zip64 stuff)
if
(
bstream
.
peekNumber
(
4
)
==
zCentralFileHeaderSignature
)
{
info
(
" Found a Central File Header"
);
// read all file headers
while
(
bstream
.
peekNumber
(
4
)
==
zCentralFileHeaderSignature
)
{
bstream
.
readNumber
(
4
);
// signature
bstream
.
readNumber
(
2
);
// version made by
bstream
.
readNumber
(
2
);
// version needed to extract
bstream
.
readNumber
(
2
);
// general purpose bit flag
bstream
.
readNumber
(
2
);
// compression method
bstream
.
readNumber
(
2
);
// last mod file time
bstream
.
readNumber
(
2
);
// last mod file date
bstream
.
readNumber
(
4
);
// crc32
bstream
.
readNumber
(
4
);
// compressed size
bstream
.
readNumber
(
4
);
// uncompressed size
var
fileNameLength
=
bstream
.
readNumber
(
2
);
// file name length
var
extraFieldLength
=
bstream
.
readNumber
(
2
);
// extra field length
var
fileCommentLength
=
bstream
.
readNumber
(
2
);
// file comment length
bstream
.
readNumber
(
2
);
// disk number start
bstream
.
readNumber
(
2
);
// internal file attributes
bstream
.
readNumber
(
4
);
// external file attributes
bstream
.
readNumber
(
4
);
// relative offset of local header
bstream
.
readString
(
fileNameLength
);
// file name
bstream
.
readString
(
extraFieldLength
);
// extra field
bstream
.
readString
(
fileCommentLength
);
// file comment
}
}
// digital signature
if
(
bstream
.
peekNumber
(
4
)
==
zDigitalSignatureSignature
)
{
info
(
" Found a Digital Signature"
);
bstream
.
readNumber
(
4
);
var
sizeOfSignature
=
bstream
.
readNumber
(
2
);
bstream
.
readString
(
sizeOfSignature
);
// digital signature data
}
// report # files and total length
if
(
localFiles
.
length
>
0
)
{
postProgress
();
}
// now do the unzipping of each file
for
(
var
i
=
0
;
i
<
localFiles
.
length
;
++
i
)
{
var
localfile
=
localFiles
[
i
];
// update progress
currentFilename
=
localfile
.
filename
;
currentFileNumber
=
i
;
currentBytesUnarchivedInFile
=
0
;
// actually do the unzipping
localfile
.
unzip
();
if
(
localfile
.
fileData
!=
null
)
{
postMessage
(
new
bitjs
.
archive
.
UnarchiveExtractEvent
(
localfile
));
postProgress
();
}
}
postProgress
();
postMessage
(
new
bitjs
.
archive
.
UnarchiveFinishEvent
());
postMessage
(
new
bitjs
.
archive
.
UnarchiveStartEvent
());
currentFilename
=
""
;
currentFileNumber
=
0
;
currentBytesUnarchivedInFile
=
0
;
currentBytesUnarchived
=
0
;
totalUncompressedBytesInArchive
=
0
;
totalFilesInArchive
=
0
;
currentBytesUnarchived
=
0
;
var
bstream
=
new
bitjs
.
io
.
ByteStream
(
arrayBuffer
);
// detect local file header signature or return null
if
(
bstream
.
peekNumber
(
4
)
==
zLocalFileHeaderSignature
)
{
var
localFiles
=
[];
// loop until we don't see any more local files
while
(
bstream
.
peekNumber
(
4
)
==
zLocalFileHeaderSignature
)
{
var
oneLocalFile
=
new
ZipLocalFile
(
bstream
);
// this should strip out directories/folders
if
(
oneLocalFile
&&
oneLocalFile
.
uncompressedSize
>
0
&&
oneLocalFile
.
fileData
)
{
localFiles
.
push
(
oneLocalFile
);
totalUncompressedBytesInArchive
+=
oneLocalFile
.
uncompressedSize
;
}
}
totalFilesInArchive
=
localFiles
.
length
;
// got all local files, now sort them
localFiles
.
sort
(
function
(
a
,
b
)
{
var
aname
=
a
.
filename
.
toLowerCase
();
var
bname
=
b
.
filename
.
toLowerCase
();
return
aname
>
bname
?
1
:
-
1
;
});
// archive extra data record
if
(
bstream
.
peekNumber
(
4
)
==
zArchiveExtraDataSignature
)
{
info
(
" Found an Archive Extra Data Signature"
);
// skipping this record for now
bstream
.
readNumber
(
4
);
var
archiveExtraFieldLength
=
bstream
.
readNumber
(
4
);
bstream
.
readString
(
archiveExtraFieldLength
);
}
// central directory structure
// TODO: handle the rest of the structures (Zip64 stuff)
if
(
bstream
.
peekNumber
(
4
)
==
zCentralFileHeaderSignature
)
{
info
(
" Found a Central File Header"
);
// read all file headers
while
(
bstream
.
peekNumber
(
4
)
==
zCentralFileHeaderSignature
)
{
bstream
.
readNumber
(
4
);
// signature
bstream
.
readNumber
(
2
);
// version made by
bstream
.
readNumber
(
2
);
// version needed to extract
bstream
.
readNumber
(
2
);
// general purpose bit flag
bstream
.
readNumber
(
2
);
// compression method
bstream
.
readNumber
(
2
);
// last mod file time
bstream
.
readNumber
(
2
);
// last mod file date
bstream
.
readNumber
(
4
);
// crc32
bstream
.
readNumber
(
4
);
// compressed size
bstream
.
readNumber
(
4
);
// uncompressed size
var
fileNameLength
=
bstream
.
readNumber
(
2
);
// file name length
var
extraFieldLength
=
bstream
.
readNumber
(
2
);
// extra field length
var
fileCommentLength
=
bstream
.
readNumber
(
2
);
// file comment length
bstream
.
readNumber
(
2
);
// disk number start
bstream
.
readNumber
(
2
);
// internal file attributes
bstream
.
readNumber
(
4
);
// external file attributes
bstream
.
readNumber
(
4
);
// relative offset of local header
bstream
.
readString
(
fileNameLength
);
// file name
bstream
.
readString
(
extraFieldLength
);
// extra field
bstream
.
readString
(
fileCommentLength
);
// file comment
}
}
// digital signature
if
(
bstream
.
peekNumber
(
4
)
==
zDigitalSignatureSignature
)
{
info
(
" Found a Digital Signature"
);
bstream
.
readNumber
(
4
);
var
sizeOfSignature
=
bstream
.
readNumber
(
2
);
bstream
.
readString
(
sizeOfSignature
);
// digital signature data
}
// report # files and total length
if
(
localFiles
.
length
>
0
)
{
postProgress
();
}
// now do the unzipping of each file
for
(
var
i
=
0
;
i
<
localFiles
.
length
;
++
i
)
{
var
localfile
=
localFiles
[
i
];
// update progress
currentFilename
=
localfile
.
filename
;
currentFileNumber
=
i
;
currentBytesUnarchivedInFile
=
0
;
// actually do the unzipping
localfile
.
unzip
();
if
(
localfile
.
fileData
!=
null
)
{
postMessage
(
new
bitjs
.
archive
.
UnarchiveExtractEvent
(
localfile
));
postProgress
();
}
}
postProgress
();
postMessage
(
new
bitjs
.
archive
.
UnarchiveFinishEvent
());
}
}
...
...
@@ -244,305 +244,305 @@ var unzip = function(arrayBuffer) {
// each entry's index is its code and its value is a JavaScript object
// containing {length: 6, symbol: X}
function
getHuffmanCodes
(
bitLengths
)
{
// ensure bitLengths is an array containing at least one element
if
(
typeof
bitLengths
!=
typeof
[]
||
bitLengths
.
length
<
1
)
{
err
(
"Error! getHuffmanCodes() called with an invalid array"
);
return
null
;
}
// Reference: http://tools.ietf.org/html/rfc1951#page-8
var
numLengths
=
bitLengths
.
length
,
bl_count
=
[],
MAX_BITS
=
1
;
// Step 1: count up how many codes of each length we have
for
(
var
i
=
0
;
i
<
numLengths
;
++
i
)
{
var
length
=
bitLengths
[
i
];
// test to ensure each bit length is a positive, non-zero number
if
(
typeof
length
!=
typeof
1
||
length
<
0
)
{
err
(
"bitLengths contained an invalid number in getHuffmanCodes(): "
+
length
+
" of type "
+
(
typeof
length
));
return
null
;
}
// increment the appropriate bitlength count
if
(
bl_count
[
length
]
==
undefined
)
bl_count
[
length
]
=
0
;
// a length of zero means this symbol is not participating in the huffman coding
if
(
length
>
0
)
bl_count
[
length
]
++
;
if
(
length
>
MAX_BITS
)
MAX_BITS
=
length
;
}
// Step 2: Find the numerical value of the smallest code for each code length
var
next_code
=
[],
code
=
0
;
for
(
var
bits
=
1
;
bits
<=
MAX_BITS
;
++
bits
)
{
var
length
=
bits
-
1
;
// ensure undefined lengths are zero
if
(
bl_count
[
length
]
==
undefined
)
bl_count
[
length
]
=
0
;
code
=
(
code
+
bl_count
[
bits
-
1
])
<<
1
;
next_code
[
bits
]
=
code
;
}
// Step 3: Assign numerical values to all codes
var
table
=
{},
tableLength
=
0
;
for
(
var
n
=
0
;
n
<
numLengths
;
++
n
)
{
var
len
=
bitLengths
[
n
];
if
(
len
!=
0
)
{
table
[
next_code
[
len
]]
=
{
length
:
len
,
symbol
:
n
};
//, bitstring: binaryValueToString(next_code[len],len) };
tableLength
++
;
next_code
[
len
]
++
;
}
}
table
.
maxLength
=
tableLength
;
return
table
;
// ensure bitLengths is an array containing at least one element
if
(
typeof
bitLengths
!=
typeof
[]
||
bitLengths
.
length
<
1
)
{
err
(
"Error! getHuffmanCodes() called with an invalid array"
);
return
null
;
}
// Reference: http://tools.ietf.org/html/rfc1951#page-8
var
numLengths
=
bitLengths
.
length
,
bl_count
=
[],
MAX_BITS
=
1
;
// Step 1: count up how many codes of each length we have
for
(
var
i
=
0
;
i
<
numLengths
;
++
i
)
{
var
length
=
bitLengths
[
i
];
// test to ensure each bit length is a positive, non-zero number
if
(
typeof
length
!=
typeof
1
||
length
<
0
)
{
err
(
"bitLengths contained an invalid number in getHuffmanCodes(): "
+
length
+
" of type "
+
(
typeof
length
));
return
null
;
}
// increment the appropriate bitlength count
if
(
bl_count
[
length
]
==
undefined
)
bl_count
[
length
]
=
0
;
// a length of zero means this symbol is not participating in the huffman coding
if
(
length
>
0
)
bl_count
[
length
]
++
;
if
(
length
>
MAX_BITS
)
MAX_BITS
=
length
;
}
// Step 2: Find the numerical value of the smallest code for each code length
var
next_code
=
[],
code
=
0
;
for
(
var
bits
=
1
;
bits
<=
MAX_BITS
;
++
bits
)
{
var
length
=
bits
-
1
;
// ensure undefined lengths are zero
if
(
bl_count
[
length
]
==
undefined
)
bl_count
[
length
]
=
0
;
code
=
(
code
+
bl_count
[
bits
-
1
])
<<
1
;
next_code
[
bits
]
=
code
;
}
// Step 3: Assign numerical values to all codes
var
table
=
{},
tableLength
=
0
;
for
(
var
n
=
0
;
n
<
numLengths
;
++
n
)
{
var
len
=
bitLengths
[
n
];
if
(
len
!=
0
)
{
table
[
next_code
[
len
]]
=
{
length
:
len
,
symbol
:
n
};
//, bitstring: binaryValueToString(next_code[len],len) };
tableLength
++
;
next_code
[
len
]
++
;
}
}
table
.
maxLength
=
tableLength
;
return
table
;
}
/*
The Huffman codes for the two alphabets are fixed, and are not
represented explicitly in the data. The Huffman code lengths
for the literal/length alphabet are:
Lit Value Bits Codes
--------- ---- -----
0 - 143 8 00110000 through
10111111
144 - 255 9 110010000 through
111111111
256 - 279 7 0000000 through
0010111
280 - 287 8 11000000 through
11000111
The Huffman codes for the two alphabets are fixed, and are not
represented explicitly in the data. The Huffman code lengths
for the literal/length alphabet are:
Lit Value Bits Codes
--------- ---- -----
0 - 143 8 00110000 through
10111111
144 - 255 9 110010000 through
111111111
256 - 279 7 0000000 through
0010111
280 - 287 8 11000000 through
11000111
*/
// fixed Huffman codes go from 7-9 bits, so we need an array whose index can hold up to 9 bits
var
fixedHCtoLiteral
=
null
;
var
fixedHCtoDistance
=
null
;
function
getFixedLiteralTable
()
{
// create once
if
(
!
fixedHCtoLiteral
)
{
var
bitlengths
=
new
Array
(
288
);
for
(
var
i
=
0
;
i
<=
143
;
++
i
)
bitlengths
[
i
]
=
8
;
for
(
i
=
144
;
i
<=
255
;
++
i
)
bitlengths
[
i
]
=
9
;
for
(
i
=
256
;
i
<=
279
;
++
i
)
bitlengths
[
i
]
=
7
;
for
(
i
=
280
;
i
<=
287
;
++
i
)
bitlengths
[
i
]
=
8
;
// get huffman code table
fixedHCtoLiteral
=
getHuffmanCodes
(
bitlengths
);
}
return
fixedHCtoLiteral
;
// create once
if
(
!
fixedHCtoLiteral
)
{
var
bitlengths
=
new
Array
(
288
);
for
(
var
i
=
0
;
i
<=
143
;
++
i
)
bitlengths
[
i
]
=
8
;
for
(
i
=
144
;
i
<=
255
;
++
i
)
bitlengths
[
i
]
=
9
;
for
(
i
=
256
;
i
<=
279
;
++
i
)
bitlengths
[
i
]
=
7
;
for
(
i
=
280
;
i
<=
287
;
++
i
)
bitlengths
[
i
]
=
8
;
// get huffman code table
fixedHCtoLiteral
=
getHuffmanCodes
(
bitlengths
);
}
return
fixedHCtoLiteral
;
}
function
getFixedDistanceTable
()
{
// create once
if
(
!
fixedHCtoDistance
)
{
var
bitlengths
=
new
Array
(
32
);
for
(
var
i
=
0
;
i
<
32
;
++
i
)
{
bitlengths
[
i
]
=
5
;
}
// get huffman code table
fixedHCtoDistance
=
getHuffmanCodes
(
bitlengths
);
}
return
fixedHCtoDistance
;
// create once
if
(
!
fixedHCtoDistance
)
{
var
bitlengths
=
new
Array
(
32
);
for
(
var
i
=
0
;
i
<
32
;
++
i
)
{
bitlengths
[
i
]
=
5
;
}
// get huffman code table
fixedHCtoDistance
=
getHuffmanCodes
(
bitlengths
);
}
return
fixedHCtoDistance
;
}
// extract one bit at a time until we find a matching Huffman Code
// then return that symbol
function
decodeSymbol
(
bstream
,
hcTable
)
{
var
code
=
0
,
len
=
0
;
var
match
=
false
;
// loop until we match
for
(;;)
{
// read in next bit
var
bit
=
bstream
.
readBits
(
1
);
code
=
(
code
<<
1
)
|
bit
;
++
len
;
// check against Huffman Code table and break if found
if
(
hcTable
.
hasOwnProperty
(
code
)
&&
hcTable
[
code
].
length
==
len
)
{
break
;
}
if
(
len
>
hcTable
.
maxLength
)
{
err
(
"Bit stream out of sync, didn't find a Huffman Code, length was "
+
len
+
" and table only max code length of "
+
hcTable
.
maxLength
);
break
;
}
}
return
hcTable
[
code
].
symbol
;
var
code
=
0
,
len
=
0
;
var
match
=
false
;
// loop until we match
for
(;;)
{
// read in next bit
var
bit
=
bstream
.
readBits
(
1
);
code
=
(
code
<<
1
)
|
bit
;
++
len
;
// check against Huffman Code table and break if found
if
(
hcTable
.
hasOwnProperty
(
code
)
&&
hcTable
[
code
].
length
==
len
)
{
break
;
}
if
(
len
>
hcTable
.
maxLength
)
{
err
(
"Bit stream out of sync, didn't find a Huffman Code, length was "
+
len
+
" and table only max code length of "
+
hcTable
.
maxLength
);
break
;
}
}
return
hcTable
[
code
].
symbol
;
}
var
CodeLengthCodeOrder
=
[
16
,
17
,
18
,
0
,
8
,
7
,
9
,
6
,
10
,
5
,
11
,
4
,
12
,
3
,
13
,
2
,
14
,
1
,
15
];
/*
Extra Extra Extra
Code Bits Length(s) Code Bits Lengths Code Bits Length(s)
---- ---- ------ ---- ---- ------- ---- ---- -------
257 0 3 267 1 15,16 277 4 67-82
258 0 4 268 1 17,18 278 4 83-98
259 0 5 269 2 19-22 279 4 99-114
260 0 6 270 2 23-26 280 4 115-130
261 0 7 271 2 27-30 281 5 131-162
262 0 8 272 2 31-34 282 5 163-194
263 0 9 273 3 35-42 283 5 195-226
264 0 10 274 3 43-50 284 5 227-257
265 1 11,12 275 3 51-58 285 0 258
266 1 13,14 276 3 59-66
*/
/*
Extra Extra Extra
Code Bits Length(s) Code Bits Lengths Code Bits Length(s)
---- ---- ------ ---- ---- ------- ---- ---- -------
257 0 3 267 1 15,16 277 4 67-82
258 0 4 268 1 17,18 278 4 83-98
259 0 5 269 2 19-22 279 4 99-114
260 0 6 270 2 23-26 280 4 115-130
261 0 7 271 2 27-30 281 5 131-162
262 0 8 272 2 31-34 282 5 163-194
263 0 9 273 3 35-42 283 5 195-226
264 0 10 274 3 43-50 284 5 227-257
265 1 11,12 275 3 51-58 285 0 258
266 1 13,14 276 3 59-66
*/
var
LengthLookupTable
=
[
[
0
,
3
],
[
0
,
4
],
[
0
,
5
],
[
0
,
6
],
[
0
,
7
],
[
0
,
8
],
[
0
,
9
],
[
0
,
10
],
[
1
,
11
],
[
1
,
13
],
[
1
,
15
],
[
1
,
17
],
[
2
,
19
],
[
2
,
23
],
[
2
,
27
],
[
2
,
31
],
[
3
,
35
],
[
3
,
43
],
[
3
,
51
],
[
3
,
59
],
[
4
,
67
],
[
4
,
83
],
[
4
,
99
],
[
4
,
115
],
[
5
,
131
],
[
5
,
163
],
[
5
,
195
],
[
5
,
227
],
[
0
,
258
]
[
0
,
3
],
[
0
,
4
],
[
0
,
5
],
[
0
,
6
],
[
0
,
7
],
[
0
,
8
],
[
0
,
9
],
[
0
,
10
],
[
1
,
11
],
[
1
,
13
],
[
1
,
15
],
[
1
,
17
],
[
2
,
19
],
[
2
,
23
],
[
2
,
27
],
[
2
,
31
],
[
3
,
35
],
[
3
,
43
],
[
3
,
51
],
[
3
,
59
],
[
4
,
67
],
[
4
,
83
],
[
4
,
99
],
[
4
,
115
],
[
5
,
131
],
[
5
,
163
],
[
5
,
195
],
[
5
,
227
],
[
0
,
258
]
];
/*
Extra Extra Extra
Code Bits Dist Code Bits Dist Code Bits Distance
---- ---- ---- ---- ---- ------ ---- ---- --------
0 0 1 10 4 33-48 20 9 1025-1536
1 0 2 11 4 49-64 21 9 1537-2048
2 0 3 12 5 65-96 22 10 2049-3072
3 0 4 13 5 97-128 23 10 3073-4096
4 1 5,6 14 6 129-192 24 11 4097-6144
5 1 7,8 15 6 193-256 25 11 6145-8192
6 2 9-12 16 7 257-384 26 12 8193-12288
7 2 13-16 17 7 385-512 27 12 12289-16384
8 3 17-24 18 8 513-768 28 13 16385-24576
9 3 25-32 19 8 769-1024 29 13 24577-32768
*/
/*
Extra Extra Extra
Code Bits Dist Code Bits Dist Code Bits Distance
---- ---- ---- ---- ---- ------ ---- ---- --------
0 0 1 10 4 33-48 20 9 1025-1536
1 0 2 11 4 49-64 21 9 1537-2048
2 0 3 12 5 65-96 22 10 2049-3072
3 0 4 13 5 97-128 23 10 3073-4096
4 1 5,6 14 6 129-192 24 11 4097-6144
5 1 7,8 15 6 193-256 25 11 6145-8192
6 2 9-12 16 7 257-384 26 12 8193-12288
7 2 13-16 17 7 385-512 27 12 12289-16384
8 3 17-24 18 8 513-768 28 13 16385-24576
9 3 25-32 19 8 769-1024 29 13 24577-32768
*/
var
DistLookupTable
=
[
[
0
,
1
],
[
0
,
2
],
[
0
,
3
],
[
0
,
4
],
[
1
,
5
],
[
1
,
7
],
[
2
,
9
],
[
2
,
13
],
[
3
,
17
],
[
3
,
25
],
[
4
,
33
],
[
4
,
49
],
[
5
,
65
],
[
5
,
97
],
[
6
,
129
],
[
6
,
193
],
[
7
,
257
],
[
7
,
385
],
[
8
,
513
],
[
8
,
769
],
[
9
,
1025
],
[
9
,
1537
],
[
10
,
2049
],
[
10
,
3073
],
[
11
,
4097
],
[
11
,
6145
],
[
12
,
8193
],
[
12
,
12289
],
[
13
,
16385
],
[
13
,
24577
]
[
0
,
1
],
[
0
,
2
],
[
0
,
3
],
[
0
,
4
],
[
1
,
5
],
[
1
,
7
],
[
2
,
9
],
[
2
,
13
],
[
3
,
17
],
[
3
,
25
],
[
4
,
33
],
[
4
,
49
],
[
5
,
65
],
[
5
,
97
],
[
6
,
129
],
[
6
,
193
],
[
7
,
257
],
[
7
,
385
],
[
8
,
513
],
[
8
,
769
],
[
9
,
1025
],
[
9
,
1537
],
[
10
,
2049
],
[
10
,
3073
],
[
11
,
4097
],
[
11
,
6145
],
[
12
,
8193
],
[
12
,
12289
],
[
13
,
16385
],
[
13
,
24577
]
];
function
inflateBlockData
(
bstream
,
hcLiteralTable
,
hcDistanceTable
,
buffer
)
{
/*
loop (until end of block code recognized)
decode literal/length value from input stream
if value < 256
copy value (literal byte) to output stream
otherwise
if value = end of block (256)
break from loop
otherwise (value = 257..285)
decode distance from input stream
move backwards distance bytes in the output
stream, and copy length bytes from this
position to the output stream.
*/
var
numSymbols
=
0
,
blockSize
=
0
;
for
(;;)
{
var
symbol
=
decodeSymbol
(
bstream
,
hcLiteralTable
);
++
numSymbols
;
if
(
symbol
<
256
)
{
// copy literal byte to output
buffer
.
insertByte
(
symbol
);
blockSize
++
;
}
else
{
// end of block reached
if
(
symbol
==
256
)
{
break
;
}
else
{
var
lengthLookup
=
LengthLookupTable
[
symbol
-
257
],
length
=
lengthLookup
[
1
]
+
bstream
.
readBits
(
lengthLookup
[
0
]),
distLookup
=
DistLookupTable
[
decodeSymbol
(
bstream
,
hcDistanceTable
)],
distance
=
distLookup
[
1
]
+
bstream
.
readBits
(
distLookup
[
0
]);
// now apply length and distance appropriately and copy to output
// TODO: check that backward distance < data.length?
// http://tools.ietf.org/html/rfc1951#page-11
// "Note also that the referenced string may overlap the current
// position; for example, if the last 2 bytes decoded have values
// X and Y, a string reference with <length = 5, distance = 2>
// adds X,Y,X,Y,X to the output stream."
//
// loop for each character
var
ch
=
buffer
.
ptr
-
distance
;
blockSize
+=
length
;
if
(
length
>
distance
)
{
var
data
=
buffer
.
data
;
while
(
length
--
)
{
buffer
.
insertByte
(
data
[
ch
++
]);
}
}
else
{
buffer
.
insertBytes
(
buffer
.
data
.
subarray
(
ch
,
ch
+
length
))
}
}
// length-distance pair
}
// length-distance pair or end-of-block
}
// loop until we reach end of block
return
blockSize
;
/*
loop (until end of block code recognized)
decode literal/length value from input stream
if value < 256
copy value (literal byte) to output stream
otherwise
if value = end of block (256)
break from loop
otherwise (value = 257..285)
decode distance from input stream
move backwards distance bytes in the output
stream, and copy length bytes from this
position to the output stream.
*/
var
numSymbols
=
0
,
blockSize
=
0
;
for
(;;)
{
var
symbol
=
decodeSymbol
(
bstream
,
hcLiteralTable
);
++
numSymbols
;
if
(
symbol
<
256
)
{
// copy literal byte to output
buffer
.
insertByte
(
symbol
);
blockSize
++
;
}
else
{
// end of block reached
if
(
symbol
==
256
)
{
break
;
}
else
{
var
lengthLookup
=
LengthLookupTable
[
symbol
-
257
],
length
=
lengthLookup
[
1
]
+
bstream
.
readBits
(
lengthLookup
[
0
]),
distLookup
=
DistLookupTable
[
decodeSymbol
(
bstream
,
hcDistanceTable
)],
distance
=
distLookup
[
1
]
+
bstream
.
readBits
(
distLookup
[
0
]);
// now apply length and distance appropriately and copy to output
// TODO: check that backward distance < data.length?
// http://tools.ietf.org/html/rfc1951#page-11
// "Note also that the referenced string may overlap the current
// position; for example, if the last 2 bytes decoded have values
// X and Y, a string reference with <length = 5, distance = 2>
// adds X,Y,X,Y,X to the output stream."
//
// loop for each character
var
ch
=
buffer
.
ptr
-
distance
;
blockSize
+=
length
;
if
(
length
>
distance
)
{
var
data
=
buffer
.
data
;
while
(
length
--
)
{
buffer
.
insertByte
(
data
[
ch
++
]);
}
}
else
{
buffer
.
insertBytes
(
buffer
.
data
.
subarray
(
ch
,
ch
+
length
))
}
}
// length-distance pair
}
// length-distance pair or end-of-block
}
// loop until we reach end of block
return
blockSize
;
}
// {Uint8Array} compressedData A Uint8Array of the compressed file data.
// compression method 8
// deflate: http://tools.ietf.org/html/rfc1951
function
inflate
(
compressedData
,
numDecompressedBytes
)
{
// Bit stream representing the compressed data.
var
bstream
=
new
bitjs
.
io
.
BitStream
(
compressedData
.
buffer
,
false
/* rtl */
,
compressedData
.
byteOffset
,
compressedData
.
byteLength
);
var
buffer
=
new
bitjs
.
io
.
ByteBuffer
(
numDecompressedBytes
);
var
numBlocks
=
0
,
blockSize
=
0
;
// block format: http://tools.ietf.org/html/rfc1951#page-9
do
{
var
bFinal
=
bstream
.
readBits
(
1
),
bType
=
bstream
.
readBits
(
2
);
blockSize
=
0
;
++
numBlocks
;
// no compression
if
(
bType
==
0
)
{
// skip remaining bits in this byte
while
(
bstream
.
bitPtr
!=
0
)
bstream
.
readBits
(
1
);
var
len
=
bstream
.
readBits
(
16
),
nlen
=
bstream
.
readBits
(
16
);
// TODO: check if nlen is the ones-complement of len?
if
(
len
>
0
)
buffer
.
insertBytes
(
bstream
.
readBytes
(
len
));
blockSize
=
len
;
}
// fixed Huffman codes
else
if
(
bType
==
1
)
{
blockSize
=
inflateBlockData
(
bstream
,
getFixedLiteralTable
(),
getFixedDistanceTable
(),
buffer
);
}
// dynamic Huffman codes
else
if
(
bType
==
2
)
{
var
numLiteralLengthCodes
=
bstream
.
readBits
(
5
)
+
257
;
var
numDistanceCodes
=
bstream
.
readBits
(
5
)
+
1
,
numCodeLengthCodes
=
bstream
.
readBits
(
4
)
+
4
;
// populate the array of code length codes (first de-compaction)
var
codeLengthsCodeLengths
=
[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
];
for
(
var
i
=
0
;
i
<
numCodeLengthCodes
;
++
i
)
{
codeLengthsCodeLengths
[
CodeLengthCodeOrder
[
i
]
]
=
bstream
.
readBits
(
3
);
}
// get the Huffman Codes for the code lengths
var
codeLengthsCodes
=
getHuffmanCodes
(
codeLengthsCodeLengths
);
// now follow this mapping
/*
// Bit stream representing the compressed data.
var
bstream
=
new
bitjs
.
io
.
BitStream
(
compressedData
.
buffer
,
false
/* rtl */
,
compressedData
.
byteOffset
,
compressedData
.
byteLength
);
var
buffer
=
new
bitjs
.
io
.
ByteBuffer
(
numDecompressedBytes
);
var
numBlocks
=
0
,
blockSize
=
0
;
// block format: http://tools.ietf.org/html/rfc1951#page-9
do
{
var
bFinal
=
bstream
.
readBits
(
1
),
bType
=
bstream
.
readBits
(
2
);
blockSize
=
0
;
++
numBlocks
;
// no compression
if
(
bType
==
0
)
{
// skip remaining bits in this byte
while
(
bstream
.
bitPtr
!=
0
)
bstream
.
readBits
(
1
);
var
len
=
bstream
.
readBits
(
16
),
nlen
=
bstream
.
readBits
(
16
);
// TODO: check if nlen is the ones-complement of len?
if
(
len
>
0
)
buffer
.
insertBytes
(
bstream
.
readBytes
(
len
));
blockSize
=
len
;
}
// fixed Huffman codes
else
if
(
bType
==
1
)
{
blockSize
=
inflateBlockData
(
bstream
,
getFixedLiteralTable
(),
getFixedDistanceTable
(),
buffer
);
}
// dynamic Huffman codes
else
if
(
bType
==
2
)
{
var
numLiteralLengthCodes
=
bstream
.
readBits
(
5
)
+
257
;
var
numDistanceCodes
=
bstream
.
readBits
(
5
)
+
1
,
numCodeLengthCodes
=
bstream
.
readBits
(
4
)
+
4
;
// populate the array of code length codes (first de-compaction)
var
codeLengthsCodeLengths
=
[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
];
for
(
var
i
=
0
;
i
<
numCodeLengthCodes
;
++
i
)
{
codeLengthsCodeLengths
[
CodeLengthCodeOrder
[
i
]
]
=
bstream
.
readBits
(
3
);
}
// get the Huffman Codes for the code lengths
var
codeLengthsCodes
=
getHuffmanCodes
(
codeLengthsCodeLengths
);
// now follow this mapping
/*
0 - 15: Represent code lengths of 0 - 15
16: Copy the previous code length 3 - 6 times.
The next 2 bits indicate repeat length
...
...
@@ -554,64 +554,64 @@ function inflate(compressedData, numDecompressedBytes) {
(3 bits of length)
18: Repeat a code length of 0 for 11 - 138 times
(7 bits of length)
*/
// to generate the true code lengths of the Huffman Codes for the literal
// and distance tables together
var
literalCodeLengths
=
[];
var
prevCodeLength
=
0
;
while
(
literalCodeLengths
.
length
<
numLiteralLengthCodes
+
numDistanceCodes
)
{
var
symbol
=
decodeSymbol
(
bstream
,
codeLengthsCodes
);
if
(
symbol
<=
15
)
{
literalCodeLengths
.
push
(
symbol
);
prevCodeLength
=
symbol
;
}
else
if
(
symbol
==
16
)
{
var
repeat
=
bstream
.
readBits
(
2
)
+
3
;
while
(
repeat
--
)
{
literalCodeLengths
.
push
(
prevCodeLength
);
}
}
else
if
(
symbol
==
17
)
{
var
repeat
=
bstream
.
readBits
(
3
)
+
3
;
while
(
repeat
--
)
{
literalCodeLengths
.
push
(
0
);
}
}
else
if
(
symbol
==
18
)
{
var
repeat
=
bstream
.
readBits
(
7
)
+
11
;
while
(
repeat
--
)
{
literalCodeLengths
.
push
(
0
);
}
}
}
// now split the distance code lengths out of the literal code array
var
distanceCodeLengths
=
literalCodeLengths
.
splice
(
numLiteralLengthCodes
,
numDistanceCodes
);
// now generate the true Huffman Code tables using these code lengths
var
hcLiteralTable
=
getHuffmanCodes
(
literalCodeLengths
),
hcDistanceTable
=
getHuffmanCodes
(
distanceCodeLengths
);
blockSize
=
inflateBlockData
(
bstream
,
hcLiteralTable
,
hcDistanceTable
,
buffer
);
}
// error
else
{
err
(
"Error! Encountered deflate block of type 3"
);
return
null
;
}
// update progress
currentBytesUnarchivedInFile
+=
blockSize
;
currentBytesUnarchived
+=
blockSize
;
postProgress
();
}
while
(
bFinal
!=
1
);
// we are done reading blocks if the bFinal bit was set for this block
// return the buffer data bytes
return
buffer
.
data
;
*/
// to generate the true code lengths of the Huffman Codes for the literal
// and distance tables together
var
literalCodeLengths
=
[];
var
prevCodeLength
=
0
;
while
(
literalCodeLengths
.
length
<
numLiteralLengthCodes
+
numDistanceCodes
)
{
var
symbol
=
decodeSymbol
(
bstream
,
codeLengthsCodes
);
if
(
symbol
<=
15
)
{
literalCodeLengths
.
push
(
symbol
);
prevCodeLength
=
symbol
;
}
else
if
(
symbol
==
16
)
{
var
repeat
=
bstream
.
readBits
(
2
)
+
3
;
while
(
repeat
--
)
{
literalCodeLengths
.
push
(
prevCodeLength
);
}
}
else
if
(
symbol
==
17
)
{
var
repeat
=
bstream
.
readBits
(
3
)
+
3
;
while
(
repeat
--
)
{
literalCodeLengths
.
push
(
0
);
}
}
else
if
(
symbol
==
18
)
{
var
repeat
=
bstream
.
readBits
(
7
)
+
11
;
while
(
repeat
--
)
{
literalCodeLengths
.
push
(
0
);
}
}
}
// now split the distance code lengths out of the literal code array
var
distanceCodeLengths
=
literalCodeLengths
.
splice
(
numLiteralLengthCodes
,
numDistanceCodes
);
// now generate the true Huffman Code tables using these code lengths
var
hcLiteralTable
=
getHuffmanCodes
(
literalCodeLengths
),
hcDistanceTable
=
getHuffmanCodes
(
distanceCodeLengths
);
blockSize
=
inflateBlockData
(
bstream
,
hcLiteralTable
,
hcDistanceTable
,
buffer
);
}
// error
else
{
err
(
"Error! Encountered deflate block of type 3"
);
return
null
;
}
// update progress
currentBytesUnarchivedInFile
+=
blockSize
;
currentBytesUnarchived
+=
blockSize
;
postProgress
();
}
while
(
bFinal
!=
1
);
// we are done reading blocks if the bFinal bit was set for this block
// return the buffer data bytes
return
buffer
.
data
;
}
// event.data.file has the ArrayBuffer.
onmessage
=
function
(
event
)
{
unzip
(
event
.
data
.
file
,
true
);
unzip
(
event
.
data
.
file
,
true
);
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment