Lines 18-26
Link Here
|
18 |
/* ==================================================================== |
18 |
/* ==================================================================== |
19 |
This product contains an ASLv2 licensed version of the OOXML signer |
19 |
This product contains an ASLv2 licensed version of the OOXML signer |
20 |
package from the eID Applet project |
20 |
package from the eID Applet project |
21 |
http://code.google.com/p/eid-applet/source/browse/trunk/README.txt |
21 |
http://code.google.com/p/eid-applet/source/browse/trunk/README.txt |
22 |
Copyright (C) 2008-2014 FedICT. |
22 |
Copyright (C) 2008-2014 FedICT. |
23 |
================================================================= */ |
23 |
================================================================= */ |
24 |
|
24 |
|
25 |
package org.apache.poi.poifs.crypt.dsig.facets; |
25 |
package org.apache.poi.poifs.crypt.dsig.facets; |
26 |
|
26 |
|
Lines 29-34
Link Here
|
29 |
import java.text.DateFormat; |
29 |
import java.text.DateFormat; |
30 |
import java.text.SimpleDateFormat; |
30 |
import java.text.SimpleDateFormat; |
31 |
import java.util.ArrayList; |
31 |
import java.util.ArrayList; |
|
|
32 |
import java.util.Arrays; |
33 |
import java.util.Collections; |
34 |
import java.util.Comparator; |
32 |
import java.util.HashSet; |
35 |
import java.util.HashSet; |
33 |
import java.util.List; |
36 |
import java.util.List; |
34 |
import java.util.Locale; |
37 |
import java.util.Locale; |
Lines 70-82
Link Here
|
70 |
|
73 |
|
71 |
/** |
74 |
/** |
72 |
* Office OpenXML Signature Facet implementation. |
75 |
* Office OpenXML Signature Facet implementation. |
73 |
* |
76 |
* |
74 |
* @author fcorneli |
|
|
75 |
* @see <a href="http://msdn.microsoft.com/en-us/library/cc313071.aspx">[MS-OFFCRYPTO]: Office Document Cryptography Structure</a> |
77 |
* @see <a href="http://msdn.microsoft.com/en-us/library/cc313071.aspx">[MS-OFFCRYPTO]: Office Document Cryptography Structure</a> |
76 |
*/ |
78 |
*/ |
77 |
public class OOXMLSignatureFacet extends SignatureFacet { |
79 |
public class OOXMLSignatureFacet extends SignatureFacet { |
78 |
|
80 |
|
79 |
private static final POILogger LOG = POILogFactory.getLogger(OOXMLSignatureFacet.class); |
81 |
private static final POILogger LOG = POILogFactory.getLogger(OOXMLSignatureFacet.class); |
|
|
82 |
private static final String ID_PACKAGE_OBJECT = "idPackageObject"; |
80 |
|
83 |
|
81 |
@Override |
84 |
@Override |
82 |
public void preSign( |
85 |
public void preSign( |
Lines 98-114
Link Here
|
98 |
List<Reference> manifestReferences = new ArrayList<Reference>(); |
101 |
List<Reference> manifestReferences = new ArrayList<Reference>(); |
99 |
addManifestReferences(manifestReferences); |
102 |
addManifestReferences(manifestReferences); |
100 |
Manifest manifest = getSignatureFactory().newManifest(manifestReferences); |
103 |
Manifest manifest = getSignatureFactory().newManifest(manifestReferences); |
101 |
|
104 |
|
102 |
String objectId = "idPackageObject"; // really has to be this value. |
|
|
103 |
List<XMLStructure> objectContent = new ArrayList<XMLStructure>(); |
105 |
List<XMLStructure> objectContent = new ArrayList<XMLStructure>(); |
104 |
objectContent.add(manifest); |
106 |
objectContent.add(manifest); |
105 |
|
107 |
|
106 |
addSignatureTime(document, objectContent); |
108 |
addSignatureTime(document, objectContent); |
107 |
|
109 |
|
108 |
XMLObject xo = getSignatureFactory().newXMLObject(objectContent, objectId, null, null); |
110 |
XMLObject xo = getSignatureFactory().newXMLObject(objectContent, ID_PACKAGE_OBJECT, null, null); |
109 |
objects.add(xo); |
111 |
objects.add(xo); |
110 |
|
112 |
|
111 |
Reference reference = newReference("#" + objectId, null, XML_DIGSIG_NS+"Object", null, null); |
113 |
Reference reference = newReference("#"+ID_PACKAGE_OBJECT, null, XML_DIGSIG_NS+"Object", null, null); |
112 |
references.add(reference); |
114 |
references.add(reference); |
113 |
} |
115 |
} |
114 |
|
116 |
|
Lines 121-127
Link Here
|
121 |
|
123 |
|
122 |
Set<String> digestedPartNames = new HashSet<String>(); |
124 |
Set<String> digestedPartNames = new HashSet<String>(); |
123 |
for (PackagePart pp : relsEntryNames) { |
125 |
for (PackagePart pp : relsEntryNames) { |
124 |
String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1"); |
126 |
final String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1"); |
125 |
|
127 |
|
126 |
PackageRelationshipCollection prc; |
128 |
PackageRelationshipCollection prc; |
127 |
try { |
129 |
try { |
Lines 130-140
Link Here
|
130 |
} catch (InvalidFormatException e) { |
132 |
} catch (InvalidFormatException e) { |
131 |
throw new XMLSignatureException("Invalid relationship descriptor: "+pp.getPartName().getName(), e); |
133 |
throw new XMLSignatureException("Invalid relationship descriptor: "+pp.getPartName().getName(), e); |
132 |
} |
134 |
} |
133 |
|
135 |
|
134 |
RelationshipTransformParameterSpec parameterSpec = new RelationshipTransformParameterSpec(); |
136 |
RelationshipTransformParameterSpec parameterSpec = new RelationshipTransformParameterSpec(); |
135 |
for (PackageRelationship relationship : prc) { |
137 |
for (PackageRelationship relationship : prc) { |
136 |
String relationshipType = relationship.getRelationshipType(); |
138 |
String relationshipType = relationship.getRelationshipType(); |
137 |
|
139 |
|
138 |
/* |
140 |
/* |
139 |
* ECMA-376 Part 2 - 3rd edition |
141 |
* ECMA-376 Part 2 - 3rd edition |
140 |
* 13.2.4.16 Manifest Element |
142 |
* 13.2.4.16 Manifest Element |
Lines 144-165
Link Here
|
144 |
continue; |
146 |
continue; |
145 |
} |
147 |
} |
146 |
|
148 |
|
147 |
if (!isSignedRelationship(relationshipType)) continue; |
149 |
if (!isSignedRelationship(relationshipType)) { |
|
|
150 |
continue; |
151 |
} |
148 |
|
152 |
|
149 |
parameterSpec.addRelationshipReference(relationship.getId()); |
153 |
parameterSpec.addRelationshipReference(relationship.getId()); |
150 |
|
154 |
|
151 |
// TODO: find a better way ... |
155 |
String partName = normalizePartName(relationship.getTargetURI(), baseUri); |
152 |
String partName = relationship.getTargetURI().toString(); |
156 |
|
153 |
if (!partName.startsWith(baseUri)) { |
157 |
// We only digest a part once. |
154 |
partName = baseUri + partName; |
158 |
if (digestedPartNames.contains(partName)) { |
|
|
159 |
continue; |
155 |
} |
160 |
} |
156 |
try { |
161 |
digestedPartNames.add(partName); |
157 |
partName = new URI(partName).normalize().getPath().replace('\\', '/'); |
162 |
|
158 |
LOG.log(POILogger.DEBUG, "part name: " + partName); |
|
|
159 |
} catch (URISyntaxException e) { |
160 |
throw new XMLSignatureException(e); |
161 |
} |
162 |
|
163 |
String contentType; |
163 |
String contentType; |
164 |
try { |
164 |
try { |
165 |
PackagePartName relName = PackagingURIHelper.createPartName(partName); |
165 |
PackagePartName relName = PackagingURIHelper.createPartName(partName); |
Lines 168-202
Link Here
|
168 |
} catch (InvalidFormatException e) { |
168 |
} catch (InvalidFormatException e) { |
169 |
throw new XMLSignatureException(e); |
169 |
throw new XMLSignatureException(e); |
170 |
} |
170 |
} |
171 |
|
171 |
|
172 |
if (relationshipType.endsWith("customXml") |
172 |
if (relationshipType.endsWith("customXml") |
173 |
&& !(contentType.equals("inkml+xml") || contentType.equals("text/xml"))) { |
173 |
&& !(contentType.equals("inkml+xml") || contentType.equals("text/xml"))) { |
174 |
LOG.log(POILogger.DEBUG, "skipping customXml with content type: " + contentType); |
174 |
LOG.log(POILogger.DEBUG, "skipping customXml with content type: " + contentType); |
175 |
continue; |
175 |
continue; |
176 |
} |
176 |
} |
177 |
|
177 |
|
178 |
if (!digestedPartNames.contains(partName)) { |
178 |
String uri = partName + "?ContentType=" + contentType; |
179 |
// We only digest a part once. |
179 |
Reference reference = newReference(uri, null, null, null, null); |
180 |
String uri = partName + "?ContentType=" + contentType; |
180 |
manifestReferences.add(reference); |
181 |
Reference reference = newReference(uri, null, null, null, null); |
|
|
182 |
manifestReferences.add(reference); |
183 |
digestedPartNames.add(partName); |
184 |
} |
185 |
} |
181 |
} |
186 |
|
182 |
|
187 |
if (parameterSpec.hasSourceIds()) { |
183 |
if (parameterSpec.hasSourceIds()) { |
188 |
List<Transform> transforms = new ArrayList<Transform>(); |
184 |
List<Transform> transforms = new ArrayList<Transform>(); |
189 |
transforms.add(newTransform(RelationshipTransformService.TRANSFORM_URI, parameterSpec)); |
185 |
transforms.add(newTransform(RelationshipTransformService.TRANSFORM_URI, parameterSpec)); |
190 |
transforms.add(newTransform(CanonicalizationMethod.INCLUSIVE)); |
186 |
transforms.add(newTransform(CanonicalizationMethod.INCLUSIVE)); |
191 |
String uri = pp.getPartName().getName() |
187 |
String uri = normalizePartName(pp.getPartName().getURI(), baseUri) |
192 |
+ "?ContentType=application/vnd.openxmlformats-package.relationships+xml"; |
188 |
+ "?ContentType=application/vnd.openxmlformats-package.relationships+xml"; |
193 |
Reference reference = newReference(uri, transforms, null, null, null); |
189 |
Reference reference = newReference(uri, transforms, null, null, null); |
194 |
manifestReferences.add(reference); |
190 |
manifestReferences.add(reference); |
195 |
} |
191 |
} |
196 |
} |
192 |
} |
|
|
193 |
|
194 |
Collections.sort(manifestReferences, new Comparator<Reference>() { |
195 |
public int compare(Reference o1, Reference o2) { |
196 |
return o1.getURI().compareTo(o2.getURI()); |
197 |
} |
198 |
}); |
197 |
} |
199 |
} |
198 |
|
200 |
|
|
|
201 |
/** |
202 |
* Normalize a URI/part name |
203 |
* TODO: find a better way ... |
204 |
*/ |
205 |
private static String normalizePartName(URI partName, String baseUri) throws XMLSignatureException { |
206 |
String pn = partName.toASCIIString(); |
207 |
if (!pn.startsWith(baseUri)) { |
208 |
pn = baseUri + pn; |
209 |
} |
210 |
try { |
211 |
pn = new URI(pn).normalize().getPath().replace('\\', '/'); |
212 |
LOG.log(POILogger.DEBUG, "part name: " + pn); |
213 |
} catch (URISyntaxException e) { |
214 |
throw new XMLSignatureException(e); |
215 |
} |
216 |
return pn; |
217 |
} |
199 |
|
218 |
|
|
|
219 |
|
200 |
protected void addSignatureTime(Document document, List<XMLStructure> objectContent) { |
220 |
protected void addSignatureTime(Document document, List<XMLStructure> objectContent) { |
201 |
/* |
221 |
/* |
202 |
* SignatureTime |
222 |
* SignatureTime |
Lines 236-242
Link Here
|
236 |
ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestMethodUri()); |
256 |
ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestMethodUri()); |
237 |
Element n = (Element)document.importNode(ctSigV1.getDomNode(), true); |
257 |
Element n = (Element)document.importNode(ctSigV1.getDomNode(), true); |
238 |
n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS); |
258 |
n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS); |
239 |
|
259 |
|
240 |
List<XMLStructure> signatureInfoContent = new ArrayList<XMLStructure>(); |
260 |
List<XMLStructure> signatureInfoContent = new ArrayList<XMLStructure>(); |
241 |
signatureInfoContent.add(new DOMStructure(n)); |
261 |
signatureInfoContent.add(new DOMStructure(n)); |
242 |
SignatureProperty signatureInfoSignatureProperty = getSignatureFactory() |
262 |
SignatureProperty signatureInfoSignatureProperty = getSignatureFactory() |
Lines 268-475
Link Here
|
268 |
|
288 |
|
269 |
protected static boolean isSignedRelationship(String relationshipType) { |
289 |
protected static boolean isSignedRelationship(String relationshipType) { |
270 |
LOG.log(POILogger.DEBUG, "relationship type: " + relationshipType); |
290 |
LOG.log(POILogger.DEBUG, "relationship type: " + relationshipType); |
271 |
for (String signedTypeExtension : signed) { |
291 |
String rt = relationshipType.replaceFirst(".*/relationships/", ""); |
272 |
if (relationshipType.endsWith(signedTypeExtension)) { |
292 |
return (signed.contains(rt) || rt.endsWith("customXml")); |
273 |
return true; |
|
|
274 |
} |
275 |
} |
276 |
if (relationshipType.endsWith("customXml")) { |
277 |
LOG.log(POILogger.DEBUG, "customXml relationship type"); |
278 |
return true; |
279 |
} |
280 |
return false; |
281 |
} |
293 |
} |
282 |
|
|
|
283 |
public static final String[] contentTypes = { |
284 |
/* |
285 |
* Word |
286 |
*/ |
287 |
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", |
288 |
"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml", |
289 |
"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", |
290 |
"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", |
291 |
"application/vnd.openxmlformats-officedocument.theme+xml", |
292 |
"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml", |
293 |
"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", |
294 |
|
294 |
|
295 |
/* |
|
|
296 |
* Word 2010 |
297 |
*/ |
298 |
"application/vnd.ms-word.stylesWithEffects+xml", |
299 |
|
300 |
/* |
301 |
* Excel |
302 |
*/ |
303 |
"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml", |
304 |
"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", |
305 |
"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", |
306 |
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", |
307 |
|
308 |
/* |
309 |
* Powerpoint |
310 |
*/ |
311 |
"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml", |
312 |
"application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml", |
313 |
"application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml", |
314 |
"application/vnd.openxmlformats-officedocument.presentationml.slide+xml", |
315 |
"application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml", |
316 |
|
317 |
/* |
318 |
* Powerpoint 2010 |
319 |
*/ |
320 |
"application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml", |
321 |
"application/vnd.openxmlformats-officedocument.presentationml.presProps+xml" |
322 |
}; |
323 |
|
324 |
/** |
295 |
/** |
325 |
* Office 2010 list of signed types (extensions). |
296 |
* Office 2010 list of signed types (extensions). |
326 |
*/ |
297 |
*/ |
327 |
public static final String[] signed = { |
298 |
private static final Set<String> signed = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList( |
328 |
"powerPivotData", // |
299 |
"activeXControlBinary","aFChunk","attachedTemplate","attachedToolbars","audio","calcChain","chart","chartColorStyle", |
329 |
"activeXControlBinary", // |
300 |
"chartLayout","chartsheet","chartStyle","chartUserShapes","commentAuthors","comments","connections","connectorXml", |
330 |
"attachedToolbars", // |
301 |
"control","ctrlProp","customData","customData","customProperty","customXml","diagram","diagramColors", |
331 |
"connectorXml", // |
302 |
"diagramColorsHeader","diagramData","diagramDrawing","diagramLayout","diagramLayoutHeader","diagramQuickStyle", |
332 |
"downRev", // |
303 |
"diagramQuickStyleHeader","dialogsheet","dictionary","documentParts","downRev","drawing","endnotes","externalLink", |
333 |
"functionPrototypes", // |
304 |
"externalLinkPath","font","fontTable","footer","footnotes","functionPrototypes","glossaryDocument","graphicFrameDoc", |
334 |
"graphicFrameDoc", // |
305 |
"groupShapeXml","handoutMaster","hdphoto","header","hyperlink","image","ink","inkXml","keyMapCustomizations", |
335 |
"groupShapeXml", // |
306 |
"legacyDiagramText","legacyDocTextInfo","mailMergeHeaderSource","mailMergeRecipientData","mailMergeSource","media", |
336 |
"ink", // |
307 |
"notesMaster","notesSlide","numbering","officeDocument","officeDocument","oleObject","package","pictureXml", |
337 |
"keyMapCustomizations", // |
308 |
"pivotCacheDefinition","pivotCacheRecords","pivotTable","powerPivotData","presProps","printerSettings","queryTable", |
338 |
"legacyDiagramText", // |
309 |
"recipientData","settings","shapeXml","sharedStrings","sheetMetadata","slicer","slicer","slicerCache","slicerCache", |
339 |
"legacyDocTextInfo", // |
310 |
"slide","slideLayout","slideMaster","slideUpdateInfo","slideUpdateUrl","smartTags","styles","stylesWithEffects", |
340 |
"officeDocument", // |
311 |
"table","tableSingleCells","tableStyles","tags","theme","themeOverride","timeline","timelineCache","transform", |
341 |
"pictureXml", // |
312 |
"ui/altText","ui/buttonSize","ui/controlID","ui/description","ui/enabled","ui/extensibility","ui/extensibility", |
342 |
"shapeXml", // |
313 |
"ui/helperText","ui/imageID","ui/imageMso","ui/keyTip","ui/label","ui/lcid","ui/loud","ui/pressed","ui/progID", |
343 |
"smartTags", // |
314 |
"ui/ribbonID","ui/showImage","ui/showLabel","ui/supertip","ui/target","ui/text","ui/title","ui/tooltip", |
344 |
"ui/altText", // |
315 |
"ui/userCustomization","ui/visible","userXmlData","vbaProject","video","viewProps","vmlDrawing", |
345 |
"ui/buttonSize", // |
316 |
"volatileDependencies","webSettings","wordVbaData","worksheet","wsSortMap","xlBinaryIndex", |
346 |
"ui/controlID", // |
317 |
"xlExternalLinkPath/xlAlternateStartup","xlExternalLinkPath/xlLibrary","xlExternalLinkPath/xlPathMissing", |
347 |
"ui/description", // |
318 |
"xlExternalLinkPath/xlStartup","xlIntlMacrosheet","xlMacrosheet","xmlMaps" |
348 |
"ui/enabled", // |
319 |
))); |
349 |
"ui/extensibility", // |
|
|
350 |
"ui/helperText", // |
351 |
"ui/imageID", // |
352 |
"ui/imageMso", // |
353 |
"ui/keyTip", // |
354 |
"ui/label", // |
355 |
"ui/lcid", // |
356 |
"ui/loud", // |
357 |
"ui/pressed", // |
358 |
"ui/progID", // |
359 |
"ui/ribbonID", // |
360 |
"ui/showImage", // |
361 |
"ui/showLabel", // |
362 |
"ui/supertip", // |
363 |
"ui/target", // |
364 |
"ui/text", // |
365 |
"ui/title", // |
366 |
"ui/tooltip", // |
367 |
"ui/userCustomization", // |
368 |
"ui/visible", // |
369 |
"userXmlData", // |
370 |
"vbaProject", // |
371 |
"wordVbaData", // |
372 |
"wsSortMap", // |
373 |
"xlBinaryIndex", // |
374 |
"xlExternalLinkPath/xlAlternateStartup", // |
375 |
"xlExternalLinkPath/xlLibrary", // |
376 |
"xlExternalLinkPath/xlPathMissing", // |
377 |
"xlExternalLinkPath/xlStartup", // |
378 |
"xlIntlMacrosheet", // |
379 |
"xlMacrosheet", // |
380 |
"customData", // |
381 |
"diagramDrawing", // |
382 |
"hdphoto", // |
383 |
"inkXml", // |
384 |
"media", // |
385 |
"slicer", // |
386 |
"slicerCache", // |
387 |
"stylesWithEffects", // |
388 |
"ui/extensibility", // |
389 |
"chartColorStyle", // |
390 |
"chartLayout", // |
391 |
"chartStyle", // |
392 |
"dictionary", // |
393 |
"timeline", // |
394 |
"timelineCache", // |
395 |
"aFChunk", // |
396 |
"attachedTemplate", // |
397 |
"audio", // |
398 |
"calcChain", // |
399 |
"chart", // |
400 |
"chartsheet", // |
401 |
"chartUserShapes", // |
402 |
"commentAuthors", // |
403 |
"comments", // |
404 |
"connections", // |
405 |
"control", // |
406 |
"customProperty", // |
407 |
"customXml", // |
408 |
"diagramColors", // |
409 |
"diagramData", // |
410 |
"diagramLayout", // |
411 |
"diagramQuickStyle", // |
412 |
"dialogsheet", // |
413 |
"drawing", // |
414 |
"endnotes", // |
415 |
"externalLink", // |
416 |
"externalLinkPath", // |
417 |
"font", // |
418 |
"fontTable", // |
419 |
"footer", // |
420 |
"footnotes", // |
421 |
"glossaryDocument", // |
422 |
"handoutMaster", // |
423 |
"header", // |
424 |
"hyperlink", // |
425 |
"image", // |
426 |
"mailMergeHeaderSource", // |
427 |
"mailMergeRecipientData", // |
428 |
"mailMergeSource", // |
429 |
"notesMaster", // |
430 |
"notesSlide", // |
431 |
"numbering", // |
432 |
"officeDocument", // |
433 |
"oleObject", // |
434 |
"package", // |
435 |
"pivotCacheDefinition", // |
436 |
"pivotCacheRecords", // |
437 |
"pivotTable", // |
438 |
"presProps", // |
439 |
"printerSettings", // |
440 |
"queryTable", // |
441 |
"recipientData", // |
442 |
"settings", // |
443 |
"sharedStrings", // |
444 |
"sheetMetadata", // |
445 |
"slide", // |
446 |
"slideLayout", // |
447 |
"slideMaster", // |
448 |
"slideUpdateInfo", // |
449 |
"slideUpdateUrl", // |
450 |
"styles", // |
451 |
"table", // |
452 |
"tableSingleCells", // |
453 |
"tableStyles", // |
454 |
"tags", // |
455 |
"theme", // |
456 |
"themeOverride", // |
457 |
"transform", // |
458 |
"video", // |
459 |
"viewProps", // |
460 |
"volatileDependencies", // |
461 |
"webSettings", // |
462 |
"worksheet", // |
463 |
"xmlMaps", // |
464 |
"ctrlProp", // |
465 |
"customData", // |
466 |
"diagram", // |
467 |
"diagramColorsHeader", // |
468 |
"diagramLayoutHeader", // |
469 |
"diagramQuickStyleHeader", // |
470 |
"documentParts", // |
471 |
"slicer", // |
472 |
"slicerCache", // |
473 |
"vmlDrawing" // |
474 |
}; |
475 |
} |
320 |
} |