2015-04-02 20:32:22 +00:00
/* [MS-DTYP] 2.3.3 FILETIME */
/* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */
/* [MS-OLEPS] 2.8 FILETIME (Packet Version) */
function parse _FILETIME ( blob ) {
var dwLowDateTime = blob . read _shift ( 4 ) , dwHighDateTime = blob . read _shift ( 4 ) ;
return new Date ( ( ( dwHighDateTime / 1e7 * Math . pow ( 2 , 32 ) + dwLowDateTime / 1e7 ) - 11644473600 ) * 1000 ) . toISOString ( ) . replace ( /\.000/ , "" ) ;
}
/* [MS-OSHARED] 2.3.3.1.4 Lpstr */
2017-07-27 20:07:51 +00:00
function parse _lpstr ( blob , type , pad /*:?number*/ ) {
2017-12-30 05:40:35 +00:00
var start = blob . l ;
var str = blob . read _shift ( 0 , 'lpstr-cp' ) ;
if ( pad ) while ( ( blob . l - start ) & 3 ) ++ blob . l ;
2015-04-02 20:32:22 +00:00
return str ;
}
/* [MS-OSHARED] 2.3.3.1.6 Lpwstr */
function parse _lpwstr ( blob , type , pad ) {
var str = blob . read _shift ( 0 , 'lpwstr' ) ;
if ( pad ) blob . l += ( 4 - ( ( str . length + 1 ) & 3 ) ) & 3 ;
return str ;
}
/* [MS-OSHARED] 2.3.3.1.11 VtString */
/* [MS-OSHARED] 2.3.3.1.12 VtUnalignedString */
function parse _VtStringBase ( blob , stringType , pad ) {
if ( stringType === 0x1F /*VT_LPWSTR*/ ) return parse _lpwstr ( blob ) ;
return parse _lpstr ( blob , stringType , pad ) ;
}
2017-08-05 06:32:57 +00:00
function parse _VtString ( blob , t /*:number*/ , pad /*:?boolean*/ ) { return parse _VtStringBase ( blob , t , pad === false ? 0 : 4 ) ; }
function parse _VtUnalignedString ( blob , t /*:number*/ ) { if ( ! t ) throw new Error ( "VtUnalignedString must have positive length" ) ; return parse _VtStringBase ( blob , t , 0 ) ; }
2015-04-02 20:32:22 +00:00
/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
2017-12-30 05:40:35 +00:00
function parse _VtVecUnalignedLpstrValue ( blob ) /*:Array<string>*/ {
2015-04-02 20:32:22 +00:00
var length = blob . read _shift ( 4 ) ;
2017-12-30 05:40:35 +00:00
var ret /*:Array<string>*/ = [ ] ;
for ( var i = 0 ; i != length ; ++ i ) ret [ i ] = blob . read _shift ( 0 , 'lpstr-cp' ) . replace ( chr0 , '' ) ;
2015-04-02 20:32:22 +00:00
return ret ;
}
/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
2017-12-30 05:40:35 +00:00
function parse _VtVecUnalignedLpstr ( blob ) /*:Array<string>*/ {
2015-04-02 20:32:22 +00:00
return parse _VtVecUnalignedLpstrValue ( blob ) ;
}
/* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */
function parse _VtHeadingPair ( blob ) {
var headingString = parse _TypedPropertyValue ( blob , VT _USTR ) ;
var headerParts = parse _TypedPropertyValue ( blob , VT _I4 ) ;
return [ headingString , headerParts ] ;
}
/* [MS-OSHARED] 2.3.3.1.14 VtVecHeadingPairValue */
function parse _VtVecHeadingPairValue ( blob ) {
var cElements = blob . read _shift ( 4 ) ;
var out = [ ] ;
for ( var i = 0 ; i != cElements / 2 ; ++ i ) out . push ( parse _VtHeadingPair ( blob ) ) ;
return out ;
}
/* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */
function parse _VtVecHeadingPair ( blob ) {
// NOTE: When invoked, wType & padding were already consumed
return parse _VtVecHeadingPairValue ( blob ) ;
}
/* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */
function parse _dictionary ( blob , CodePage ) {
var cnt = blob . read _shift ( 4 ) ;
2017-03-05 00:56:31 +00:00
var dict /*:{[number]:string}*/ = ( { } /*:any*/ ) ;
2015-04-02 20:32:22 +00:00
for ( var j = 0 ; j != cnt ; ++ j ) {
var pid = blob . read _shift ( 4 ) ;
var len = blob . read _shift ( 4 ) ;
dict [ pid ] = blob . read _shift ( len , ( CodePage === 0x4B0 ? 'utf16le' : 'utf8' ) ) . replace ( chr0 , '' ) . replace ( chr1 , '!' ) ;
}
if ( blob . l & 3 ) blob . l = ( blob . l >> 2 + 1 ) << 2 ;
return dict ;
}
/* [MS-OLEPS] 2.9 BLOB */
function parse _BLOB ( blob ) {
var size = blob . read _shift ( 4 ) ;
var bytes = blob . slice ( blob . l , blob . l + size ) ;
2017-02-10 19:23:01 +00:00
if ( ( size & 3 ) > 0 ) blob . l += ( 4 - ( size & 3 ) ) & 3 ;
2015-04-02 20:32:22 +00:00
return bytes ;
}
/* [MS-OLEPS] 2.11 ClipboardData */
function parse _ClipboardData ( blob ) {
// TODO
var o = { } ;
o . Size = blob . read _shift ( 4 ) ;
//o.Format = blob.read_shift(4);
blob . l += o . Size ;
return o ;
}
/* [MS-OLEPS] 2.14 Vector and Array Property Types */
function parse _VtVector ( blob , cb ) {
/* [MS-OLEPS] 2.14.2 VectorHeader */
/ * v a r L e n g t h = b l o b . r e a d _ s h i f t ( 4 ) ;
var o = [ ] ;
for ( var i = 0 ; i != Length ; ++ i ) {
o . push ( cb ( blob ) ) ;
}
return o ; * /
}
/* [MS-OLEPS] 2.15 TypedPropertyValue */
2017-10-17 00:14:32 +00:00
function parse _TypedPropertyValue ( blob , type /*:number*/ , _opts ) /*:any*/ {
2015-04-02 20:32:22 +00:00
var t = blob . read _shift ( 2 ) , ret , opts = _opts || { } ;
blob . l += 2 ;
if ( type !== VT _VARIANT )
if ( t !== type && VT _CUSTOM . indexOf ( type ) === - 1 ) throw new Error ( 'Expected type ' + type + ' saw ' + t ) ;
switch ( type === VT _VARIANT ? t : type ) {
case 0x02 /*VT_I2*/ : ret = blob . read _shift ( 2 , 'i' ) ; if ( ! opts . raw ) blob . l += 2 ; return ret ;
case 0x03 /*VT_I4*/ : ret = blob . read _shift ( 4 , 'i' ) ; return ret ;
case 0x0B /*VT_BOOL*/ : return blob . read _shift ( 4 ) !== 0x0 ;
case 0x13 /*VT_UI4*/ : ret = blob . read _shift ( 4 ) ; return ret ;
case 0x1E /*VT_LPSTR*/ : return parse _lpstr ( blob , t , 4 ) . replace ( chr0 , '' ) ;
case 0x1F /*VT_LPWSTR*/ : return parse _lpwstr ( blob ) ;
case 0x40 /*VT_FILETIME*/ : return parse _FILETIME ( blob ) ;
case 0x41 /*VT_BLOB*/ : return parse _BLOB ( blob ) ;
case 0x47 /*VT_CF*/ : return parse _ClipboardData ( blob ) ;
2017-08-05 06:32:57 +00:00
case 0x50 /*VT_STRING*/ : return parse _VtString ( blob , t , ! opts . raw ) . replace ( chr0 , '' ) ;
2017-07-05 22:27:54 +00:00
case 0x51 /*VT_USTR*/ : return parse _VtUnalignedString ( blob , t /*, 4*/ ) . replace ( chr0 , '' ) ;
2015-04-02 20:32:22 +00:00
case 0x100C /*VT_VECTOR|VT_VARIANT*/ : return parse _VtVecHeadingPair ( blob ) ;
case 0x101E /*VT_LPSTR*/ : return parse _VtVecUnalignedLpstr ( blob ) ;
default : throw new Error ( "TypedPropertyValue unrecognized type " + type + " " + t ) ;
}
}
/* [MS-OLEPS] 2.14.2 VectorHeader */
/ * f u n c t i o n p a r s e _ V T V e c t o r V a r i a n t ( b l o b ) {
var Length = blob . read _shift ( 4 ) ;
if ( Length & 1 !== 0 ) throw new Error ( "VectorHeader Length=" + Length + " must be even" ) ;
var o = [ ] ;
for ( var i = 0 ; i != Length ; ++ i ) {
o . push ( parse _TypedPropertyValue ( blob , VT _VARIANT ) ) ;
}
return o ;
} * /
/* [MS-OLEPS] 2.20 PropertySet */
function parse _PropertySet ( blob , PIDSI ) {
var start _addr = blob . l ;
var size = blob . read _shift ( 4 ) ;
var NumProps = blob . read _shift ( 4 ) ;
var Props = [ ] , i = 0 ;
var CodePage = 0 ;
2017-03-05 00:56:31 +00:00
var Dictionary = - 1 , DictObj /*:{[number]:string}*/ = ( { } /*:any*/ ) ;
2015-04-02 20:32:22 +00:00
for ( i = 0 ; i != NumProps ; ++ i ) {
var PropID = blob . read _shift ( 4 ) ;
var Offset = blob . read _shift ( 4 ) ;
Props [ i ] = [ PropID , Offset + start _addr ] ;
}
2017-12-30 05:40:35 +00:00
Props . sort ( function ( x , y ) { return x [ 1 ] - y [ 1 ] ; } ) ;
2015-04-02 20:32:22 +00:00
var PropH = { } ;
for ( i = 0 ; i != NumProps ; ++ i ) {
if ( blob . l !== Props [ i ] [ 1 ] ) {
var fail = true ;
if ( i > 0 && PIDSI ) switch ( PIDSI [ Props [ i - 1 ] [ 0 ] ] . t ) {
2017-12-30 05:40:35 +00:00
case 0x02 /*VT_I2*/ : if ( blob . l + 2 === Props [ i ] [ 1 ] ) { blob . l += 2 ; fail = false ; } break ;
2015-04-02 20:32:22 +00:00
case 0x50 /*VT_STRING*/ : if ( blob . l <= Props [ i ] [ 1 ] ) { blob . l = Props [ i ] [ 1 ] ; fail = false ; } break ;
case 0x100C /*VT_VECTOR|VT_VARIANT*/ : if ( blob . l <= Props [ i ] [ 1 ] ) { blob . l = Props [ i ] [ 1 ] ; fail = false ; } break ;
}
2017-12-30 05:40:35 +00:00
if ( ( ! PIDSI || i == 0 ) && blob . l <= Props [ i ] [ 1 ] ) { fail = false ; blob . l = Props [ i ] [ 1 ] ; }
2015-04-02 20:32:22 +00:00
if ( fail ) throw new Error ( "Read Error: Expected address " + Props [ i ] [ 1 ] + ' at ' + blob . l + ' :' + i ) ;
}
if ( PIDSI ) {
var piddsi = PIDSI [ Props [ i ] [ 0 ] ] ;
PropH [ piddsi . n ] = parse _TypedPropertyValue ( blob , piddsi . t , { raw : true } ) ;
if ( piddsi . p === 'version' ) PropH [ piddsi . n ] = String ( PropH [ piddsi . n ] >> 16 ) + "." + String ( PropH [ piddsi . n ] & 0xFFFF ) ;
if ( piddsi . n == "CodePage" ) switch ( PropH [ piddsi . n ] ) {
case 0 : PropH [ piddsi . n ] = 1252 ;
/* falls through */
2017-05-09 18:07:57 +00:00
case 874 :
case 932 :
case 936 :
case 949 :
case 950 :
case 1250 :
case 1251 :
case 1253 :
case 1254 :
case 1255 :
case 1256 :
case 1257 :
case 1258 :
case 10000 :
case 1200 :
case 1201 :
case 1252 :
case 65000 : case - 536 :
case 65001 : case - 535 :
2017-10-17 00:14:32 +00:00
set _cp ( CodePage = ( PropH [ piddsi . n ] >>> 0 ) & 0xFFFF ) ; break ;
2015-04-02 20:32:22 +00:00
default : throw new Error ( "Unsupported CodePage: " + PropH [ piddsi . n ] ) ;
}
} else {
if ( Props [ i ] [ 0 ] === 0x1 ) {
2017-10-17 00:14:32 +00:00
CodePage = PropH . CodePage = ( parse _TypedPropertyValue ( blob , VT _I2 ) /*:number*/ ) ;
2015-04-02 20:32:22 +00:00
set _cp ( CodePage ) ;
if ( Dictionary !== - 1 ) {
var oldpos = blob . l ;
blob . l = Props [ Dictionary ] [ 1 ] ;
DictObj = parse _dictionary ( blob , CodePage ) ;
blob . l = oldpos ;
}
} else if ( Props [ i ] [ 0 ] === 0 ) {
if ( CodePage === 0 ) { Dictionary = i ; blob . l = Props [ i + 1 ] [ 1 ] ; continue ; }
DictObj = parse _dictionary ( blob , CodePage ) ;
} else {
var name = DictObj [ Props [ i ] [ 0 ] ] ;
var val ;
/* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
switch ( blob [ blob . l ] ) {
case 0x41 /*VT_BLOB*/ : blob . l += 4 ; val = parse _BLOB ( blob ) ; break ;
case 0x1E /*VT_LPSTR*/ : blob . l += 4 ; val = parse _VtString ( blob , blob [ blob . l - 4 ] ) ; break ;
case 0x1F /*VT_LPWSTR*/ : blob . l += 4 ; val = parse _VtString ( blob , blob [ blob . l - 4 ] ) ; break ;
case 0x03 /*VT_I4*/ : blob . l += 4 ; val = blob . read _shift ( 4 , 'i' ) ; break ;
case 0x13 /*VT_UI4*/ : blob . l += 4 ; val = blob . read _shift ( 4 ) ; break ;
case 0x05 /*VT_R8*/ : blob . l += 4 ; val = blob . read _shift ( 8 , 'f' ) ; break ;
case 0x0B /*VT_BOOL*/ : blob . l += 4 ; val = parsebool ( blob , 4 ) ; break ;
2017-03-23 01:18:40 +00:00
case 0x40 /*VT_FILETIME*/ : blob . l += 4 ; val = parseDate ( parse _FILETIME ( blob ) ) ; break ;
2015-04-02 20:32:22 +00:00
default : throw new Error ( "unparsed value: " + blob [ blob . l ] ) ;
}
PropH [ name ] = val ;
}
}
}
blob . l = start _addr + size ; /* step ahead to skip padding */
return PropH ;
}
/* [MS-OLEPS] 2.21 PropertySetStream */
function parse _PropertySetStream ( file , PIDSI ) {
var blob = file . content ;
2017-09-30 06:18:11 +00:00
if ( ! blob ) return ( { } /*:any*/ ) ;
2015-04-02 20:32:22 +00:00
prep _blob ( blob , 0 ) ;
2017-02-10 19:23:01 +00:00
var NumSets , FMTID0 , FMTID1 , Offset0 , Offset1 = 0 ;
2015-04-02 20:32:22 +00:00
blob . chk ( 'feff' , 'Byte Order: ' ) ;
var vers = blob . read _shift ( 2 ) ; // TODO: check version
var SystemIdentifier = blob . read _shift ( 4 ) ;
blob . chk ( CFB . utils . consts . HEADER _CLSID , 'CLSID: ' ) ;
NumSets = blob . read _shift ( 4 ) ;
2017-03-27 21:35:15 +00:00
if ( NumSets !== 1 && NumSets !== 2 ) throw new Error ( "Unrecognized #Sets: " + NumSets ) ;
2015-04-02 20:32:22 +00:00
FMTID0 = blob . read _shift ( 16 ) ; Offset0 = blob . read _shift ( 4 ) ;
2017-03-27 21:35:15 +00:00
if ( NumSets === 1 && Offset0 !== blob . l ) throw new Error ( "Length mismatch: " + Offset0 + " !== " + blob . l ) ;
2015-04-02 20:32:22 +00:00
else if ( NumSets === 2 ) { FMTID1 = blob . read _shift ( 16 ) ; Offset1 = blob . read _shift ( 4 ) ; }
var PSet0 = parse _PropertySet ( blob , PIDSI ) ;
2017-02-10 19:23:01 +00:00
var rval = ( { SystemIdentifier : SystemIdentifier } /*:any*/ ) ;
2015-04-02 20:32:22 +00:00
for ( var y in PSet0 ) rval [ y ] = PSet0 [ y ] ;
//rval.blob = blob;
rval . FMTID = FMTID0 ;
//rval.PSet0 = PSet0;
if ( NumSets === 1 ) return rval ;
2017-02-10 19:23:01 +00:00
if ( blob . l !== Offset1 ) throw new Error ( "Length mismatch 2: " + blob . l + " !== " + Offset1 ) ;
2015-04-02 20:32:22 +00:00
var PSet1 ;
2017-05-09 18:07:57 +00:00
try { PSet1 = parse _PropertySet ( blob , null ) ; } catch ( e ) { /* empty */ }
2015-04-02 20:32:22 +00:00
for ( y in PSet1 ) rval [ y ] = PSet1 [ y ] ;
rval . FMTID = [ FMTID0 , FMTID1 ] ; // TODO: verify FMTID0/1
return rval ;
}
function parsenoop2 ( blob , length ) { blob . read _shift ( length ) ; return null ; }
2017-09-22 22:18:51 +00:00
function writezeroes ( n , o ) { if ( ! o ) o = new _buf ( n ) ; for ( var j = 0 ; j < n ; ++ j ) o . write _shift ( 1 , 0 ) ; return o ; }
2015-04-02 20:32:22 +00:00
function parslurp ( blob , length , cb ) {
var arr = [ ] , target = blob . l + length ;
while ( blob . l < target ) arr . push ( cb ( blob , target - blob . l ) ) ;
if ( target !== blob . l ) throw new Error ( "Slurp error" ) ;
return arr ;
}
2017-09-22 22:18:51 +00:00
function parsebool ( blob , length /*:number*/ ) { return blob . read _shift ( length ) === 0x1 ; }
function writebool ( v /*:any*/ , o ) { if ( ! o ) o = new _buf ( 2 ) ; o . write _shift ( 2 , + ! ! v ) ; return o ; }
2015-04-02 20:32:22 +00:00
2017-07-05 22:27:54 +00:00
function parseuint16 ( blob /*::, length:?number, opts:?any*/ ) { return blob . read _shift ( 2 , 'u' ) ; }
2017-09-22 22:18:51 +00:00
function writeuint16 ( v /*:number*/ , o ) { if ( ! o ) o = new _buf ( 2 ) ; o . write _shift ( 2 , v ) ; return o ; }
2017-07-05 22:27:54 +00:00
function parseuint16a ( blob , length /*:: :?number, opts:?any*/ ) { return parslurp ( blob , length , parseuint16 ) ; }
2015-04-02 20:32:22 +00:00
/* --- 2.5 Structures --- */
/* [MS-XLS] 2.5.10 Bes (boolean or error) */
2017-07-05 22:27:54 +00:00
function parse _Bes ( blob /*::, length*/ ) {
2015-04-02 20:32:22 +00:00
var v = blob . read _shift ( 1 ) , t = blob . read _shift ( 1 ) ;
return t === 0x01 ? v : v === 0x01 ;
}
2017-09-22 22:18:51 +00:00
function write _Bes ( v , t /*:string*/ , o ) {
if ( ! o ) o = new _buf ( 2 ) ;
o . write _shift ( 1 , + v ) ;
o . write _shift ( 1 , t == 'e' ? 1 : 0 ) ;
return o ;
}
2015-04-02 20:32:22 +00:00
/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
function parse _ShortXLUnicodeString ( blob , length , opts ) {
2017-02-19 20:36:32 +00:00
var cch = blob . read _shift ( opts && opts . biff >= 12 ? 2 : 1 ) ;
2015-04-02 20:32:22 +00:00
var width = 1 , encoding = 'sbcs-cont' ;
var cp = current _codepage ;
if ( opts && opts . biff >= 8 ) current _codepage = 1200 ;
2017-02-19 20:36:32 +00:00
if ( ! opts || opts . biff == 8 ) {
2015-04-02 20:32:22 +00:00
var fHighByte = blob . read _shift ( 1 ) ;
if ( fHighByte ) { width = 2 ; encoding = 'dbcs-cont' ; }
2017-02-19 20:36:32 +00:00
} else if ( opts . biff == 12 ) {
width = 2 ; encoding = 'wstr' ;
2015-04-02 20:32:22 +00:00
}
2018-01-11 08:01:25 +00:00
if ( opts . biff >= 2 && opts . biff <= 5 ) encoding = 'cpstr' ;
2015-04-02 20:32:22 +00:00
var o = cch ? blob . read _shift ( cch , encoding ) : "" ;
current _codepage = cp ;
return o ;
}
/* 2.5.293 XLUnicodeRichExtendedString */
function parse _XLUnicodeRichExtendedString ( blob ) {
var cp = current _codepage ;
current _codepage = 1200 ;
var cch = blob . read _shift ( 2 ) , flags = blob . read _shift ( 1 ) ;
var fHighByte = flags & 0x1 , fExtSt = flags & 0x4 , fRichSt = flags & 0x8 ;
var width = 1 + ( flags & 0x1 ) ; // 0x0 -> utf8, 0x1 -> dbcs
2017-02-10 19:23:01 +00:00
var cRun = 0 , cbExtRst ;
2015-04-02 20:32:22 +00:00
var z = { } ;
if ( fRichSt ) cRun = blob . read _shift ( 2 ) ;
if ( fExtSt ) cbExtRst = blob . read _shift ( 4 ) ;
2017-12-30 05:40:35 +00:00
var encoding = width == 2 ? 'dbcs-cont' : 'sbcs-cont' ;
2015-04-02 20:32:22 +00:00
var msg = cch === 0 ? "" : blob . read _shift ( cch , encoding ) ;
if ( fRichSt ) blob . l += 4 * cRun ; //TODO: parse this
if ( fExtSt ) blob . l += cbExtRst ; //TODO: parse this
z . t = msg ;
if ( ! fRichSt ) { z . raw = "<t>" + z . t + "</t>" ; z . r = z . t ; }
current _codepage = cp ;
return z ;
}
/* 2.5.296 XLUnicodeStringNoCch */
function parse _XLUnicodeStringNoCch ( blob , cch , opts ) {
var retval ;
2017-02-19 20:36:32 +00:00
if ( opts ) {
2018-01-11 08:01:25 +00:00
if ( opts . biff >= 2 && opts . biff <= 5 ) return blob . read _shift ( cch , 'cpstr' ) ;
2017-02-19 20:36:32 +00:00
if ( opts . biff >= 12 ) return blob . read _shift ( cch , 'dbcs-cont' ) ;
}
2015-04-02 20:32:22 +00:00
var fHighByte = blob . read _shift ( 1 ) ;
if ( fHighByte === 0 ) { retval = blob . read _shift ( cch , 'sbcs-cont' ) ; }
else { retval = blob . read _shift ( cch , 'dbcs-cont' ) ; }
return retval ;
}
/* 2.5.294 XLUnicodeString */
function parse _XLUnicodeString ( blob , length , opts ) {
2017-02-19 20:36:32 +00:00
var cch = blob . read _shift ( opts && opts . biff == 2 ? 1 : 2 ) ;
2015-04-02 20:32:22 +00:00
if ( cch === 0 ) { blob . l ++ ; return "" ; }
return parse _XLUnicodeStringNoCch ( blob , cch , opts ) ;
}
/* BIFF5 override */
function parse _XLUnicodeString2 ( blob , length , opts ) {
2017-02-10 19:23:01 +00:00
if ( opts . biff > 5 ) return parse _XLUnicodeString ( blob , length , opts ) ;
2015-04-02 20:32:22 +00:00
var cch = blob . read _shift ( 1 ) ;
if ( cch === 0 ) { blob . l ++ ; return "" ; }
2018-01-11 08:01:25 +00:00
return blob . read _shift ( cch , ( opts . biff <= 4 || ! blob . lens ) ? 'cpstr' : 'sbcs-cont' ) ;
2015-04-02 20:32:22 +00:00
}
2017-10-27 16:25:54 +00:00
/* TODO: BIFF5 and lower, codepage awareness */
function write _XLUnicodeString ( str , opts , o ) {
if ( ! o ) o = new _buf ( 3 + 2 * str . length ) ;
o . write _shift ( 2 , str . length ) ;
o . write _shift ( 1 , 1 ) ;
o . write _shift ( 31 , str , 'utf16le' ) ;
return o ;
}
2015-04-02 20:32:22 +00:00
/* [MS-XLS] 2.5.61 ControlInfo */
2017-07-26 08:35:28 +00:00
function parse _ControlInfo ( blob , length , opts ) {
var flags = blob . read _shift ( 1 ) ;
blob . l ++ ;
var accel = blob . read _shift ( 2 ) ;
blob . l += 2 ;
return [ flags , accel ] ;
}
2015-04-02 20:32:22 +00:00
/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
2017-09-22 22:18:51 +00:00
function parse _URLMoniker ( blob /*::, length, opts*/ ) {
2015-04-02 20:32:22 +00:00
var len = blob . read _shift ( 4 ) , start = blob . l ;
var extra = false ;
if ( len > 24 ) {
/* look ahead */
blob . l += len - 24 ;
if ( blob . read _shift ( 16 ) === "795881f43b1d7f48af2c825dc4852763" ) extra = true ;
blob . l = start ;
}
var url = blob . read _shift ( ( extra ? len - 24 : len ) >> 1 , 'utf16le' ) . replace ( chr0 , "" ) ;
if ( extra ) blob . l += 24 ;
return url ;
2017-09-22 22:18:51 +00:00
}
2015-04-02 20:32:22 +00:00
/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
2017-09-22 22:18:51 +00:00
function parse _FileMoniker ( blob , length ) {
2015-04-02 20:32:22 +00:00
var cAnti = blob . read _shift ( 2 ) ;
2017-12-30 05:40:35 +00:00
var ansiPath = blob . read _shift ( 0 , 'lpstr-ansi' ) ;
2015-04-02 20:32:22 +00:00
var endServer = blob . read _shift ( 2 ) ;
2017-12-30 05:40:35 +00:00
if ( blob . read _shift ( 2 ) != 0xDEAD ) throw new Error ( "Bad FileMoniker" ) ;
var sz = blob . read _shift ( 4 ) ;
if ( sz === 0 ) return ansiPath . replace ( /\\/g , "/" ) ;
var bytes = blob . read _shift ( 4 ) ;
if ( blob . read _shift ( 2 ) != 3 ) throw new Error ( "Bad FileMoniker" ) ;
var unicodePath = blob . read _shift ( bytes >> 1 , 'utf16le' ) . replace ( chr0 , "" ) ;
2015-04-02 20:32:22 +00:00
return unicodePath ;
2017-09-22 22:18:51 +00:00
}
2015-04-02 20:32:22 +00:00
/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
2017-09-22 22:18:51 +00:00
function parse _HyperlinkMoniker ( blob , length ) {
2015-04-02 20:32:22 +00:00
var clsid = blob . read _shift ( 16 ) ; length -= 16 ;
switch ( clsid ) {
case "e0c9ea79f9bace118c8200aa004ba90b" : return parse _URLMoniker ( blob , length ) ;
case "0303000000000000c000000000000046" : return parse _FileMoniker ( blob , length ) ;
2017-03-27 21:35:15 +00:00
default : throw new Error ( "Unsupported Moniker " + clsid ) ;
2015-04-02 20:32:22 +00:00
}
2017-09-22 22:18:51 +00:00
}
2015-04-02 20:32:22 +00:00
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
2017-09-22 22:18:51 +00:00
function parse _HyperlinkString ( blob , length ) {
2015-04-02 20:32:22 +00:00
var len = blob . read _shift ( 4 ) ;
2017-12-15 01:18:40 +00:00
var o = len > 0 ? blob . read _shift ( len , 'utf16le' ) . replace ( chr0 , "" ) : "" ;
2015-04-02 20:32:22 +00:00
return o ;
2017-09-22 22:18:51 +00:00
}
2015-04-02 20:32:22 +00:00
2017-12-15 01:18:40 +00:00
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
function parse _Hyperlink ( blob , length ) /*:Hyperlink*/ {
2015-04-02 20:32:22 +00:00
var end = blob . l + length ;
var sVer = blob . read _shift ( 4 ) ;
if ( sVer !== 2 ) throw new Error ( "Unrecognized streamVersion: " + sVer ) ;
var flags = blob . read _shift ( 2 ) ;
blob . l += 2 ;
2017-12-15 01:18:40 +00:00
var displayName , targetFrameName , moniker , oleMoniker , Location = "" , guid , fileTime ;
2015-04-02 20:32:22 +00:00
if ( flags & 0x0010 ) displayName = parse _HyperlinkString ( blob , end - blob . l ) ;
if ( flags & 0x0080 ) targetFrameName = parse _HyperlinkString ( blob , end - blob . l ) ;
if ( ( flags & 0x0101 ) === 0x0101 ) moniker = parse _HyperlinkString ( blob , end - blob . l ) ;
if ( ( flags & 0x0101 ) === 0x0001 ) oleMoniker = parse _HyperlinkMoniker ( blob , end - blob . l ) ;
2017-12-15 01:18:40 +00:00
if ( flags & 0x0008 ) Location = parse _HyperlinkString ( blob , end - blob . l ) ;
2015-04-02 20:32:22 +00:00
if ( flags & 0x0020 ) guid = blob . read _shift ( 16 ) ;
2017-07-26 08:35:28 +00:00
if ( flags & 0x0040 ) fileTime = parse _FILETIME ( blob /*, 8*/ ) ;
2015-04-02 20:32:22 +00:00
blob . l = end ;
2017-12-15 01:18:40 +00:00
var target = targetFrameName || moniker || oleMoniker || "" ;
if ( target && Location ) target += "#" + Location ;
if ( ! target ) target = "#" + Location ;
2015-04-02 20:32:22 +00:00
return { Target : target } ;
2017-09-22 22:18:51 +00:00
}
2017-12-15 01:18:40 +00:00
function write _Hyperlink ( hl ) {
var out = new _buf ( 512 ) , i = 0 ;
var Target = hl . Target ;
var F = Target . indexOf ( "#" ) > - 1 ? 0x1f : 0x17 ;
switch ( Target . charAt ( 0 ) ) { case "#" : F = 0x1c ; break ; case "." : F &= ~ 2 ; break ; }
out . write _shift ( 4 , 2 ) ; out . write _shift ( 4 , F ) ;
var data = [ 8 , 6815827 , 6619237 , 4849780 , 83 ] ; for ( i = 0 ; i < data . length ; ++ i ) out . write _shift ( 4 , data [ i ] ) ;
if ( F == 0x1C ) {
Target = Target . slice ( 1 ) ;
out . write _shift ( 4 , Target . length + 1 ) ;
for ( i = 0 ; i < Target . length ; ++ i ) out . write _shift ( 2 , Target . charCodeAt ( i ) ) ;
out . write _shift ( 2 , 0 ) ;
} else if ( F & 0x02 ) {
data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b" . split ( " " ) ;
for ( i = 0 ; i < data . length ; ++ i ) out . write _shift ( 1 , parseInt ( data [ i ] , 16 ) ) ;
out . write _shift ( 4 , 2 * ( Target . length + 1 ) ) ;
for ( i = 0 ; i < Target . length ; ++ i ) out . write _shift ( 2 , Target . charCodeAt ( i ) ) ;
out . write _shift ( 2 , 0 ) ;
} else {
data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46" . split ( " " ) ;
for ( i = 0 ; i < data . length ; ++ i ) out . write _shift ( 1 , parseInt ( data [ i ] , 16 ) ) ;
var P = 0 ;
while ( Target . slice ( P * 3 , P * 3 + 3 ) == "../" || Target . slice ( P * 3 , P * 3 + 3 ) == "..\\" ) ++ P ;
out . write _shift ( 2 , P ) ;
out . write _shift ( 4 , Target . length + 1 ) ;
for ( i = 0 ; i < Target . length ; ++ i ) out . write _shift ( 1 , Target . charCodeAt ( i ) & 0xFF ) ;
out . write _shift ( 1 , 0 ) ;
out . write _shift ( 2 , 0xFFFF ) ;
out . write _shift ( 2 , 0xDEAD ) ;
for ( i = 0 ; i < 6 ; ++ i ) out . write _shift ( 4 , 0 ) ;
}
return out . slice ( 0 , out . l ) ;
}
2015-04-02 20:32:22 +00:00
/* 2.5.178 LongRGBA */
function parse _LongRGBA ( blob , length ) { var r = blob . read _shift ( 1 ) , g = blob . read _shift ( 1 ) , b = blob . read _shift ( 1 ) , a = blob . read _shift ( 1 ) ; return [ r , g , b , a ] ; }
/* 2.5.177 LongRGB */
function parse _LongRGB ( blob , length ) { var x = parse _LongRGBA ( blob , length ) ; x [ 3 ] = 0 ; return x ; }