| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.royale.compiler.internal.targets; |
| |
| import java.io.File; |
| import java.text.ParseException; |
| import java.text.SimpleDateFormat; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Map.Entry; |
| |
| import org.apache.royale.abc.ABCConstants; |
| import org.apache.royale.abc.instructionlist.InstructionList; |
| import org.apache.royale.abc.semantics.Label; |
| import org.apache.royale.abc.semantics.Name; |
| import org.apache.royale.abc.visitors.ITraitVisitor; |
| import org.apache.royale.abc.visitors.ITraitsVisitor; |
| import org.apache.royale.compiler.common.VersionInfo; |
| import org.apache.royale.compiler.config.RSLSettings; |
| import org.apache.royale.compiler.config.RSLSettings.RSLAndPolicyFileURLPair; |
| import org.apache.royale.compiler.constants.IASLanguageConstants; |
| import org.apache.royale.compiler.constants.IMetaAttributeConstants; |
| import org.apache.royale.compiler.definitions.IDefinition; |
| import org.apache.royale.compiler.definitions.metadata.IMetaTag; |
| import org.apache.royale.compiler.definitions.references.IResolvedQualifiersReference; |
| import org.apache.royale.compiler.definitions.references.ReferenceFactory; |
| import org.apache.royale.compiler.internal.abc.ClassGeneratorHelper; |
| import org.apache.royale.compiler.internal.as.codegen.LexicalScope; |
| import org.apache.royale.compiler.internal.config.FrameInfo; |
| import org.apache.royale.compiler.internal.definitions.ClassDefinition; |
| import org.apache.royale.compiler.internal.definitions.NamespaceDefinition; |
| import org.apache.royale.compiler.internal.projects.RoyaleProject; |
| import org.apache.royale.compiler.internal.targets.Target.DirectDependencies; |
| import org.apache.royale.compiler.mxml.IMXMLTypeConstants; |
| import org.apache.royale.compiler.problems.ICompilerProblem; |
| import org.apache.royale.compiler.problems.InvalidBackgroundColorProblem; |
| import org.apache.royale.compiler.problems.MissingSignedDigestProblem; |
| import org.apache.royale.compiler.problems.MissingUnsignedDigestProblem; |
| import org.apache.royale.compiler.targets.ITargetSettings; |
| import org.apache.royale.compiler.tree.as.IASNode; |
| import org.apache.royale.compiler.units.ICompilationUnit; |
| import org.apache.royale.compiler.units.requests.IFileScopeRequestResult; |
| import org.apache.royale.swc.ISWC; |
| import org.apache.royale.swc.ISWCDigest; |
| import org.apache.royale.swc.ISWCLibrary; |
| import org.apache.royale.swc.ISWCManager; |
| import org.apache.royale.swf.ISWF; |
| import org.apache.royale.swf.tags.ProductInfoTag; |
| import org.apache.royale.swf.tags.ProductInfoTag.Edition; |
| import org.apache.royale.swf.tags.ProductInfoTag.Product; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Iterables; |
| |
| import static org.apache.royale.compiler.mxml.IMXMLLanguageConstants.*; |
| |
| /** |
| * Delegate class used by Royale specific targets to generate Royale specific code. |
| * If we were writing this compiler in C++ this would be a mix-in class. |
| */ |
| public abstract class RoyaleTarget |
| { |
| public RoyaleTarget(ITargetSettings targetSettings, RoyaleProject project) |
| { |
| royaleProject = project; |
| this.targetSettings = targetSettings; |
| |
| accessibleClassNames = new HashSet<String>(); |
| } |
| |
| protected final RoyaleProject royaleProject; |
| private final ITargetSettings targetSettings; |
| |
| /** |
| * {@link Set} of classes referenced from accessibility meta-data. |
| * <p> |
| * For Example: |
| * <p> |
| * {@code [AccessibilityClass(implementation="mx.accessibility.ButtonAccImpl")]} |
| * <p> |
| * This set is accumulated as we discover direct dependencies, which is not as |
| * maintainable as I would like. |
| */ |
| protected final HashSet<String> accessibleClassNames; |
| |
| /** |
| * Codegen IFlexModuleFactory.callInContext(); |
| * |
| * public final override function callInContext(fn:Function, thisArg:Object, argArray:Array, returns:Boolean=true) : * |
| * { |
| * var ret : * = fn.apply(thisArg, argArray); |
| * if (returns) return ret; |
| * return; |
| * } |
| * |
| * @param classGen |
| * @param isOverride true if the generated method overrides a base class |
| * method, false otherwise. |
| */ |
| protected final void codegenCallInContextMethod(ClassGeneratorHelper classGen, boolean isOverride) |
| { |
| IResolvedQualifiersReference applyReference = ReferenceFactory.resolvedQualifierQualifiedReference(royaleProject.getWorkspace(), |
| NamespaceDefinition.getAS3NamespaceDefinition(), "apply"); |
| |
| InstructionList callInContext = new InstructionList(); |
| callInContext.addInstruction(ABCConstants.OP_getlocal1); |
| callInContext.addInstruction(ABCConstants.OP_getlocal2); |
| callInContext.addInstruction(ABCConstants.OP_getlocal3); |
| callInContext.addInstruction(ABCConstants.OP_callproperty, new Object[] {applyReference.getMName(), 2}); |
| callInContext.addInstruction(ABCConstants.OP_getlocal, 4); |
| Label callInContextReturnVoid = new Label(); |
| callInContext.addInstruction(ABCConstants.OP_iffalse, callInContextReturnVoid); |
| callInContext.addInstruction(ABCConstants.OP_returnvalue); |
| callInContext.labelNext(callInContextReturnVoid); |
| // TODO This should be OP_returnvoid, but the Boolean default value |
| // for the 'returns' parameter isn't defaulting to true. |
| // Fix this after CMP-936 is fixed. |
| callInContext.addInstruction(ABCConstants.OP_returnvalue); |
| |
| ImmutableList<Name> callInContextParams = new ImmutableList.Builder<Name>() |
| .add(new Name(IASLanguageConstants.Function)) |
| .add(new Name(IASLanguageConstants.Object)) |
| .add(new Name(IASLanguageConstants.Array)) |
| .add(new Name(IASLanguageConstants.Boolean)) |
| .build(); |
| |
| classGen.addITraitsMethod(new Name("callInContext"), callInContextParams, null, |
| Collections.<Object> singletonList(Boolean.TRUE), false, true, isOverride, callInContext); |
| |
| } |
| |
| /** |
| * Codegen IFlexModuleFactory.create() override public function create(... |
| * params):Object { var mainClass : Class; if (params.length <= 0) { |
| * mainClass = getlex MainApplicationClass } else if (params[0] is String) { |
| * mainClass = getDefinitionByName(params[0]) } else return |
| * super.create.apply(this, params); if (!mainClass) return null; var |
| * instance:Object = new mainClass(); if (instance is IFlexModule) |
| * (IFlexModule(instance)).moduleFactory = this; return instance; } |
| * |
| * @param classGen |
| * @param mainApplicationName {@link Name} that will refer to the main |
| * application class at runtme. May not be null but a library.swf for a SWC |
| * may pass in a {@link Name} that resolves to "Object" at runtime. |
| */ |
| protected final void codegenCreateMethod(ClassGeneratorHelper classGen, Name mainApplicationName, boolean isFlexSDKInfo) |
| { |
| IResolvedQualifiersReference applyReference = ReferenceFactory.resolvedQualifierQualifiedReference(royaleProject.getWorkspace(), |
| NamespaceDefinition.getAS3NamespaceDefinition(), "apply"); |
| IResolvedQualifiersReference getDefinitionByNameReference = |
| ReferenceFactory.packageQualifiedReference(royaleProject.getWorkspace(), IASLanguageConstants.getDefinitionByName); |
| IResolvedQualifiersReference iFlexModule = |
| ReferenceFactory.packageQualifiedReference(royaleProject.getWorkspace(), IMXMLTypeConstants.IFlexModule); |
| boolean codegenIFlexModule = iFlexModule.resolve(royaleProject) != null && isFlexSDKInfo; |
| Name getDefinitionByName = getDefinitionByNameReference.getMName(); |
| InstructionList create = new InstructionList(); |
| create.addInstruction(ABCConstants.OP_getlocal1); |
| create.addInstruction(ABCConstants.OP_getproperty, new Name("length")); |
| create.addInstruction(ABCConstants.OP_pushbyte, 0); |
| Label createL1 = new Label(); |
| create.addInstruction(ABCConstants.OP_ifgt, createL1); |
| create.addInstruction(ABCConstants.OP_findproperty, mainApplicationName); |
| create.addInstruction(ABCConstants.OP_getproperty, mainApplicationName); |
| Label createL3 = new Label(); |
| create.addInstruction(ABCConstants.OP_jump, createL3); |
| create.labelNext(createL1); |
| create.addInstruction(ABCConstants.OP_getlocal1); |
| create.addInstruction(ABCConstants.OP_getproperty, new Name("0")); |
| create.addInstruction(ABCConstants.OP_istype, new Name("String")); |
| Label createL2 = new Label(); |
| create.addInstruction(ABCConstants.OP_iffalse, createL2); |
| create.addInstruction(ABCConstants.OP_finddef, getDefinitionByName); |
| create.addInstruction(ABCConstants.OP_getlocal1); |
| create.addInstruction(ABCConstants.OP_getproperty, new Name("0")); |
| create.addInstruction(ABCConstants.OP_callproperty, new Object[] {getDefinitionByName, 1}); |
| create.addInstruction(ABCConstants.OP_jump, createL3); |
| create.labelNext(createL2); |
| create.addInstruction(ABCConstants.OP_getlocal0); |
| create.addInstruction(ABCConstants.OP_getsuper, new Name("create")); |
| create.addInstruction(ABCConstants.OP_getlocal0); |
| create.addInstruction(ABCConstants.OP_getlocal1); |
| create.addInstruction(ABCConstants.OP_callproperty, new Object[] {applyReference.getMName(), 2}); |
| create.addInstruction(ABCConstants.OP_returnvalue); |
| create.labelNext(createL3); |
| create.addInstruction(ABCConstants.OP_astype, new Name("Class")); |
| create.addInstruction(ABCConstants.OP_dup); |
| Label createL5 = new Label(); |
| create.addInstruction(ABCConstants.OP_iffalse, createL5); |
| create.addInstruction(ABCConstants.OP_construct, 0); |
| if (codegenIFlexModule) |
| { |
| create.addInstruction(ABCConstants.OP_dup); |
| create.addInstruction(ABCConstants.OP_istype, iFlexModule.getMName()); |
| Label createL4 = new Label(); |
| create.addInstruction(ABCConstants.OP_iffalse, createL4); |
| create.addInstruction(ABCConstants.OP_dup); |
| create.addInstruction(ABCConstants.OP_getlocal0); |
| create.addInstruction(ABCConstants.OP_setproperty, new Name("moduleFactory")); |
| create.labelNext(createL4); |
| create.addInstruction(ABCConstants.OP_returnvalue); |
| } |
| create.labelNext(createL5); |
| create.addInstruction(ABCConstants.OP_returnvalue); |
| classGen.addITraitsMethod(new Name("create"), Collections.<Name> emptyList(), |
| new Name("Object"), Collections.emptyList(), true, true, true, create); |
| |
| } |
| |
| /** |
| * Codegen the IFlexModuleFactory.info() method. |
| * |
| * public override final function info() : Object |
| * { |
| * if (!_info) |
| * { |
| * _info = { |
| * currentDomain : ApplicationDomain.currentDomain |
| * . |
| * . |
| * . |
| * } |
| * } |
| * } |
| * |
| * @param classGen used to create the function |
| * @param compatibilityVersion compatibility version set in the compiler option. |
| * May be null if not configured. |
| * @param mainClassQName qName of the main class of the application. May be null |
| * of library swfs. |
| * @param preloaderReference reference to the configured preloader class. |
| * May be null for library swfs. |
| * @param runtimeDPIProviderReference configured runtimeDPIProvider. May be null |
| * for library swfs. |
| * @param splashScreen reference to the configured splash screen. |
| * @param rootNode root node of the application. May be null for library swfs. |
| * @param compiledLocales the locales supported by this application. May be null for |
| * library swfs. |
| * @param rsls legacy RSLs. May be null for library swfs. |
| * @param problemCollection problems found when generating the info method |
| * are added to the collection. |
| * @param remoteClassAliasMap |
| * @throws InterruptedException |
| */ |
| |
| protected final void codegenInfoMethod(ClassGeneratorHelper classGen, |
| Integer compatibilityVersion, |
| String mainClassQName, |
| IResolvedQualifiersReference preloaderReference, |
| IResolvedQualifiersReference runtimeDPIProviderReference, |
| FlexSplashScreenImage splashScreen, |
| IASNode rootNode, |
| ITargetAttributes targetAttributes, |
| Collection<String> compiledLocales, |
| RoyaleFrame1Info frame1Info, |
| Set<String> accessibilityClassNames, |
| String royaleInitClassName, |
| String stylesClassName, |
| List<String> rsls, |
| FlexRSLInfo rslInfo, |
| Collection<ICompilerProblem> problemCollection, |
| boolean isAppFlexInfo, |
| boolean isFlexSDKInfo, |
| Map<ClassDefinition, String> remoteClassAliasMap) |
| throws InterruptedException |
| { |
| IResolvedQualifiersReference applicationDomainRef = ReferenceFactory.packageQualifiedReference(royaleProject.getWorkspace(), |
| IASLanguageConstants.ApplicationDomain); |
| IResolvedQualifiersReference infoSlotReference; |
| if (isAppFlexInfo) |
| { |
| NamespaceDefinition.IStaticProtectedNamespaceDefinition staticNSDef = NamespaceDefinition.createStaticProtectedNamespaceDefinition(""); |
| infoSlotReference = ReferenceFactory.resolvedQualifierQualifiedReference(royaleProject.getWorkspace(), |
| staticNSDef, "_info"); |
| } |
| else |
| { |
| NamespaceDefinition.IPrivateNamespaceDefinition privateNSDef = NamespaceDefinition.createPrivateNamespaceDefinition(""); |
| infoSlotReference = ReferenceFactory.resolvedQualifierQualifiedReference(royaleProject.getWorkspace(), |
| privateNSDef, "info"); |
| } |
| Name infoSlotName = infoSlotReference.getMName(); |
| |
| InstructionList info = new InstructionList(); |
| info.addInstruction(ABCConstants.OP_getlocal0); |
| info.addInstruction(ABCConstants.OP_getproperty, infoSlotName); |
| info.addInstruction(ABCConstants.OP_dup); |
| Label infoL1 = new Label(); |
| info.addInstruction(ABCConstants.OP_iftrue, infoL1); |
| |
| int infoEntries = 0; |
| |
| // currentDomain: |
| info.addInstruction(ABCConstants.OP_pop); |
| info.addInstruction(ABCConstants.OP_pushstring, "currentDomain"); |
| info.addInstruction(ABCConstants.OP_getlex, applicationDomainRef.getMName()); |
| info.addInstruction(ABCConstants.OP_getproperty, new Name("currentDomain")); |
| infoEntries++; |
| |
| // frames: |
| if (targetSettings.getFrameLabels() != null && !targetSettings.getFrameLabels().isEmpty()) |
| { |
| Collection<FrameInfo> frames = targetSettings.getFrameLabels(); |
| info.addInstruction(ABCConstants.OP_pushstring, "frames"); |
| for (FrameInfo frame : frames) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, frame.getLabel()); |
| info.addInstruction(ABCConstants.OP_convert_s); |
| info.addInstruction(ABCConstants.OP_pushstring, frame.getFrameClasses().get(0)); |
| } |
| info.addInstruction(ABCConstants.OP_newobject, frames.size()); |
| infoEntries++; |
| } |
| |
| // royaleVersion: |
| if (compatibilityVersion != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "royaleVersion"); |
| info.addInstruction(ABCConstants.OP_pushstring, compatibilityVersion); |
| infoEntries++; |
| } |
| |
| // mark this SWF as being built with Royale |
| info.addInstruction(ABCConstants.OP_pushstring, "isMXMLC"); |
| info.addInstruction(ABCConstants.OP_pushfalse); |
| infoEntries++; |
| |
| // mainClassName: |
| if (mainClassQName != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "mainClassName"); |
| info.addInstruction(ABCConstants.OP_pushstring, mainClassQName); |
| infoEntries++; |
| } |
| |
| if (!isAppFlexInfo && isFlexSDKInfo) |
| { |
| // preloader: |
| if (preloaderReference != null && preloaderReference.resolve(royaleProject) != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, ATTRIBUTE_PRELOADER); |
| info.addInstruction(ABCConstants.OP_getlex, preloaderReference.getMName()); |
| infoEntries++; |
| } |
| |
| // runtimeDPIProvider: |
| if (runtimeDPIProviderReference != null && runtimeDPIProviderReference.resolve(royaleProject) != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, ATTRIBUTE_RUNTIME_DPI_PROVIDER); |
| info.addInstruction(ABCConstants.OP_getlex, runtimeDPIProviderReference.getMName()); |
| infoEntries++; |
| } |
| |
| // splashScreenImage: |
| if (splashScreen.generatedEmbedClassReference != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, ATTRIBUTE_SPLASH_SCREEN_IMAGE); |
| info.addInstruction(ABCConstants.OP_getlex, splashScreen.generatedEmbedClassReference.getMName()); |
| infoEntries++; |
| } |
| |
| // Add various root node attributes: |
| infoEntries += codegenRootNodeAttributes(targetAttributes, info, rootNode, problemCollection); |
| |
| // compiledLocales: |
| if (compiledLocales != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "compiledLocales"); |
| for(String locale : compiledLocales) |
| info.addInstruction(ABCConstants.OP_pushstring, locale); |
| info.addInstruction(ABCConstants.OP_newarray, compiledLocales.size()); |
| infoEntries++; |
| } |
| |
| // compiledResourceBundleNames: |
| if (!frame1Info.compiledResourceBundleNames.isEmpty()) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "compiledResourceBundleNames"); |
| for(String bundleName : frame1Info.compiledResourceBundleNames) |
| info.addInstruction(ABCConstants.OP_pushstring, bundleName); |
| info.addInstruction(ABCConstants.OP_newarray, frame1Info.compiledResourceBundleNames.size()); |
| infoEntries++; |
| } |
| } |
| |
| // styleDataClassName |
| if (stylesClassName != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "styleDataClassName"); |
| info.addInstruction(ABCConstants.OP_pushstring, stylesClassName); |
| infoEntries++; |
| } |
| |
| // mixins: |
| if (royaleInitClassName != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "mixins"); |
| info.addInstruction(ABCConstants.OP_pushstring, royaleInitClassName); |
| int mixinEntries = 1; |
| final Set<String> mixinClassNames = frame1Info.getMixins(); |
| for (String className : frame1Info.getMixins()) |
| info.addInstruction(ABCConstants.OP_pushstring, className); |
| |
| mixinEntries += mixinClassNames.size(); |
| |
| info.addInstruction(ABCConstants.OP_newarray, mixinEntries); |
| infoEntries++; |
| } |
| |
| if (remoteClassAliasMap != null && !remoteClassAliasMap.isEmpty()) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "remoteClassAliases"); |
| for (Map.Entry<ClassDefinition, String> classAliasEntry : remoteClassAliasMap.entrySet()) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, classAliasEntry.getKey().getQualifiedName()); |
| info.addInstruction(ABCConstants.OP_convert_s); |
| String value = classAliasEntry.getValue(); |
| info.addInstruction(ABCConstants.OP_pushstring, value); |
| } |
| info.addInstruction(ABCConstants.OP_newobject, remoteClassAliasMap.size()); |
| infoEntries++; |
| } |
| |
| // fonts: |
| if (!frame1Info.embeddedFonts.isEmpty()) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "fonts"); |
| for (Entry<String, RoyaleFontInfo> entry : frame1Info.embeddedFonts.entrySet()) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, entry.getKey()); |
| info.addInstruction(ABCConstants.OP_convert_s); |
| RoyaleFontInfo fontInfo = entry.getValue(); |
| info.addInstruction(ABCConstants.OP_pushstring, "regular"); |
| info.addInstruction(fontInfo.regularOp); |
| info.addInstruction(ABCConstants.OP_pushstring, "bold"); |
| info.addInstruction(fontInfo.boldOp); |
| info.addInstruction(ABCConstants.OP_pushstring, "italic"); |
| info.addInstruction(fontInfo.italicOp); |
| info.addInstruction(ABCConstants.OP_pushstring, "boldItalic"); |
| info.addInstruction(fontInfo.boldItalicOp); |
| info.addInstruction(ABCConstants.OP_newobject, 4); |
| } |
| info.addInstruction(ABCConstants.OP_newobject, frame1Info.embeddedFonts.size()); |
| infoEntries++; |
| } |
| |
| // accessibility classes |
| if (accessibilityClassNames != null && accessibilityClassNames.size() > 0) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "accessibilityClassNames"); |
| for (String className : accessibilityClassNames) |
| info.addInstruction(ABCConstants.OP_pushstring, className); |
| |
| info.addInstruction(ABCConstants.OP_newarray, accessibilityClassNames.size()); |
| infoEntries++; |
| } |
| |
| // cdRSLs and placeholderRSLs: |
| if (!rslInfo.requiredRSLs.isEmpty()) |
| { |
| // Note: The Flex framework spells this info property as Rsl, not RSL. |
| if (codegenRSLsEntry(info, problemCollection, "cdRsls", rslInfo.requiredRSLs)) |
| infoEntries++; |
| |
| // Note: The Flex framework spells this info property as Rsl, not RSL. |
| if (codegenRSLsEntry(info, problemCollection, "placeholderRsls", rslInfo.placeholderRSLs)) |
| infoEntries++; |
| } |
| |
| // rsls: |
| if (codegenLegacyRSLs(info, rsls)) |
| infoEntries++; |
| |
| // Create a new info object from all of the entries. |
| info.addInstruction(ABCConstants.OP_newobject, infoEntries); |
| info.addInstruction(ABCConstants.OP_dup); |
| info.addInstruction(ABCConstants.OP_getlocal0); |
| info.addInstruction(ABCConstants.OP_swap); |
| info.addInstruction(ABCConstants.OP_setproperty, infoSlotName); |
| info.labelNext(infoL1); |
| info.addInstruction(ABCConstants.OP_returnvalue); |
| |
| ITraitsVisitor itraitsVisitor; |
| ITraitVisitor infoSlotVisitor; |
| if (isAppFlexInfo) |
| { |
| classGen.addCTraitsMethod(new Name("info"), Collections.<Name> emptyList(), |
| new Name("Object"), Collections.emptyList(), false, info); |
| itraitsVisitor = classGen.getCTraitsVisitor(); |
| infoSlotVisitor = itraitsVisitor.visitSlotTrait(ABCConstants.TRAIT_Var, infoSlotName, |
| ITraitsVisitor.RUNTIME_SLOT, new Name(IASLanguageConstants.Object), LexicalScope.noInitializer); |
| } |
| else |
| { |
| classGen.addITraitsMethod(new Name("info"), Collections.<Name> emptyList(), |
| new Name("Object"), Collections.emptyList(), false, true, true, info); |
| itraitsVisitor = classGen.getITraitsVisitor(); |
| infoSlotVisitor = itraitsVisitor.visitSlotTrait(ABCConstants.TRAIT_Var, infoSlotName, |
| ITraitsVisitor.RUNTIME_SLOT, new Name(IASLanguageConstants.Object), LexicalScope.noInitializer); |
| } |
| |
| infoSlotVisitor.visitStart(); |
| infoSlotVisitor.visitEnd(); |
| |
| } |
| |
| /** |
| * Generate code to add root node attributes to the info object that haven't |
| * already been handled. |
| * |
| * @param info |
| * @return number of entries added to the info object |
| * @throws InterruptedException |
| */ |
| private int codegenRootNodeAttributes(ITargetAttributes targetAttributes, InstructionList info, |
| IASNode rootNode, |
| Collection<ICompilerProblem> problemCollection) throws InterruptedException |
| { |
| // Number of attributes added to the "info" object. |
| int entries = 0; |
| |
| // Emit "info" attributes that don't require special processing. |
| final Map<String, String> attributes = targetAttributes.getRootInfoAttributes(); |
| for (final Map.Entry<String, String> e : attributes.entrySet()) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, e.getKey()); |
| info.addInstruction(ABCConstants.OP_pushstring, e.getValue()); |
| entries++; |
| } |
| |
| // Emit "info.usePreloader" as a boolean value. |
| final Boolean usePreloader = targetAttributes.getUsePreloader(); |
| if (usePreloader != null) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, ATTRIBUTE_USE_PRELOADER); |
| info.addInstruction(usePreloader ? ABCConstants.OP_pushtrue : ABCConstants.OP_pushfalse); |
| entries++; |
| } |
| |
| // Emit "info.backgroundColor" as a hex string value. |
| final String backgroundColorString = targetAttributes.getBackgroundColor(); |
| if (backgroundColorString != null) |
| { |
| try |
| { |
| final int backgroundColor = royaleProject.getColorAsInt(backgroundColorString); |
| final String hexString = "0x" + Integer.toHexString(backgroundColor).toUpperCase(); |
| info.addInstruction(ABCConstants.OP_pushstring, ATTRIBUTE_BACKGROUND_COLOR); |
| info.addInstruction(ABCConstants.OP_pushstring, hexString); |
| entries++; |
| } |
| catch (NumberFormatException numberFormatExpression) |
| { |
| problemCollection.add(new InvalidBackgroundColorProblem( |
| rootNode.getFileSpecification().getPath(), |
| backgroundColorString)); |
| } |
| } |
| |
| return entries; |
| } |
| |
| /** |
| * Generate either the "cdRsls" or "placeholderRsls" entry in the |
| * IFlexModuleFactory info function. |
| * |
| * @param info |
| * @param problemCollection |
| * @param entryLabel the "info" entry label |
| * @param rslSettingsList the rsls for the entry |
| * |
| * @return true if instructions were added for the RSLs, false otherwise. |
| */ |
| private boolean codegenRSLsEntry(InstructionList info, Collection<ICompilerProblem> problemCollection, |
| String entryLabel, |
| List<RSLSettings> rslSettingsList) |
| { |
| ISWCManager swcManager = royaleProject.getWorkspace().getSWCManager(); |
| |
| info.addInstruction(ABCConstants.OP_pushstring, entryLabel); |
| |
| IResolvedQualifiersReference mxCoreRSLDataReference = |
| ReferenceFactory.packageQualifiedReference(royaleProject.getWorkspace(), IMXMLTypeConstants.RSLData); |
| Name mxCoreRSLDataSlotName = mxCoreRSLDataReference.getMName(); |
| Object[] mxCoreRSLDataCtor = new Object[] { mxCoreRSLDataSlotName, 7 }; |
| |
| // Add an RSLData instance to an array for the primary RSL in RSLSettings |
| // plus one for every failover RSL. |
| for (RSLSettings rslSettings : rslSettingsList) |
| { |
| int rslCount = 0; |
| for (RSLAndPolicyFileURLPair urls : rslSettings.getRSLURLs()) |
| { |
| info.addInstruction(ABCConstants.OP_findpropstrict, mxCoreRSLDataSlotName); |
| info.addInstruction(ABCConstants.OP_pushstring, urls.getRSLURL()); |
| info.addInstruction(ABCConstants.OP_pushstring, urls.getPolicyFileURL()); |
| |
| ISWC swc = swcManager.get(new File(rslSettings.getLibraryFile().getPath())); |
| |
| boolean isSignedRSL = RSLSettings.isSignedRSL(urls.getRSLURL()); |
| ISWCDigest swcDigest = getSWCDigest(Iterables.getFirst(swc.getLibraries(), null), |
| isSignedRSL); |
| |
| if (swcDigest == null) |
| { |
| if (isSignedRSL) |
| problemCollection.add(new MissingSignedDigestProblem(swc.getSWCFile().getAbsolutePath())); |
| else |
| problemCollection.add(new MissingUnsignedDigestProblem(swc.getSWCFile().getAbsolutePath())); |
| |
| continue; |
| } |
| |
| info.addInstruction(ABCConstants.OP_pushstring, swcDigest.getValue()); |
| info.addInstruction(ABCConstants.OP_pushstring, swcDigest.getType()); |
| info.addInstruction(isSignedRSL ? ABCConstants.OP_pushtrue : ABCConstants.OP_pushfalse); |
| info.addInstruction(rslSettings.getVerifyDigest() ? ABCConstants.OP_pushtrue : ABCConstants.OP_pushfalse); |
| info.addInstruction(ABCConstants.OP_pushstring, |
| rslSettings.getApplicationDomain().getApplicationDomainValue()); |
| |
| info.addInstruction(ABCConstants.OP_constructprop, mxCoreRSLDataCtor); |
| rslCount++; |
| } |
| |
| info.addInstruction(ABCConstants.OP_newarray, rslCount); |
| } |
| |
| info.addInstruction(ABCConstants.OP_newarray, rslSettingsList.size()); |
| |
| return true; |
| } |
| |
| /** |
| * Get either a signed or unsigned digest from the library. |
| * |
| * @param swcLibrary |
| * @param signedDigest if true return a signed digest, otherwise an unsigned digest. |
| * @return A signed or unsigned digest. Null if the requested digest is not |
| * available. |
| */ |
| private ISWCDigest getSWCDigest(ISWCLibrary swcLibrary, boolean signedDigest) |
| { |
| for (ISWCDigest swcDigest : swcLibrary.getDigests()) |
| { |
| if (swcDigest.isSigned() == signedDigest) |
| return swcDigest; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * rsls: [{url: "rsl1.swf", size: -1}, {url: "rsl2.swf", size: -1}, {url: "rsl3.swf", size: -1}] |
| * |
| * @param info |
| * @return |
| */ |
| private boolean codegenLegacyRSLs(InstructionList info, List<String> rsls) |
| { |
| if (rsls != null && rsls.size() > 0) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "rsls"); |
| for (String rsl : rsls) |
| { |
| info.addInstruction(ABCConstants.OP_pushstring, "url"); |
| info.addInstruction(ABCConstants.OP_pushstring, rsl); |
| info.addInstruction(ABCConstants.OP_pushstring, "size"); |
| info.addInstruction(ABCConstants.OP_pushbyte, -1); |
| info.addInstruction(ABCConstants.OP_newobject, 2); |
| } |
| |
| info.addInstruction(ABCConstants.OP_newarray, rsls.size()); |
| } |
| |
| return rsls != null && rsls.size() > 0; |
| } |
| |
| |
| |
| static final Target.DirectDependencies NO_DEPENDENCIES = |
| new Target.DirectDependencies(Collections.<ICompilationUnit>emptyList(), Collections.<ICompilerProblem>emptyList()); |
| |
| /** |
| * Find the accessible compilation units on a set of compilation units. The |
| * accessible compilation units are gathered from the |
| * {@code [AccessiblityClass]} meta-data on a class. |
| * <p> |
| * Unfortunately this method has a side effect, it updates the set of |
| * accessibility classes. |
| * |
| * @param compilationUnit A compilation unit. |
| * @return A {@link DirectDependencies} object with the set of compilation |
| * units representing the new compilation units needed for accessibility. If |
| * no accessible compilation units are found or accessibility is not enabled |
| * on the target, then the returned {@link DirectDependencies} object will |
| * contain an empty set. |
| */ |
| public Target.DirectDependencies getAccessibilityDependencies(ICompilationUnit compilationUnit) throws InterruptedException |
| { |
| assert targetSettings.isAccessible() : "This method should only be called if accessibility is enabled!"; |
| Set<ICompilationUnit> accessibleCompilationUnits = new HashSet<ICompilationUnit>(); |
| IFileScopeRequestResult result = compilationUnit.getFileScopeRequest().get(); |
| |
| for(IDefinition def : result.getExternallyVisibleDefinitions()) |
| { |
| IMetaTag md = def.getMetaTagByName(IMetaAttributeConstants.ATTRIBUTE_ACCESSIBIlITY_CLASS); |
| if (md == null) |
| continue; |
| |
| String accessibilityClass = md.getAttributeValue(IMetaAttributeConstants.NAME_ACCESSIBILITY_IMPLEMENTATION); |
| if (accessibilityClass == null) |
| continue; |
| |
| IResolvedQualifiersReference ref = ReferenceFactory.packageQualifiedReference(royaleProject.getWorkspace(), |
| accessibilityClass); |
| assert ref != null; |
| |
| // Collect a list of classes to add to the info structure. |
| accessibleClassNames.add(accessibilityClass); |
| |
| IDefinition accessibilityClassDefinition = ref.resolve(royaleProject); |
| if ((accessibilityClassDefinition != null) && (!accessibilityClassDefinition.isImplicit())) |
| { |
| ICompilationUnit cu = royaleProject.getScope().getCompilationUnitForDefinition(accessibilityClassDefinition); |
| assert cu != null : "Unable to find compilation unit for definition!"; |
| accessibleCompilationUnits.add(cu); |
| } |
| } |
| |
| return new Target.DirectDependencies(accessibleCompilationUnits, Collections.<ICompilerProblem>emptyList()); |
| } |
| |
| /** |
| * Update the SWF model by adding a ProductInfoTag. |
| * |
| * @param swf the swf model to update. |
| */ |
| public void addProductInfoToSWF(ISWF swf) |
| { |
| long compileDate = new Date().getTime(); |
| String rdfDate = targetSettings.getSWFMetadataDate(); |
| String rdfDateFormat = targetSettings.getSWFMetadataDateFormat(); |
| if (rdfDate != null && rdfDateFormat != null) |
| { |
| try { |
| SimpleDateFormat sdf = new SimpleDateFormat(rdfDateFormat); |
| compileDate = sdf.parse(rdfDate).getTime(); |
| } catch (ParseException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } catch (IllegalArgumentException e1) { |
| e1.printStackTrace(); |
| } |
| } |
| // Add product info to the swf. |
| ProductInfoTag productInfo = new ProductInfoTag(Product.ROYALE, |
| Edition.NONE, |
| (byte)Integer.parseInt(VersionInfo.FLEX_MAJOR_VERSION), |
| (byte)Integer.parseInt(VersionInfo.FLEX_MINOR_VERSION), |
| VersionInfo.getBuildLong(), |
| compileDate); |
| swf.setProductInfo(productInfo); |
| } |
| } |