1 /* 2 * Copyright the original author or authors. 3 * 4 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.mozilla.org/MPL/MPL-1.1.html 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import org.as2lib.core.BasicClass; 18 19 /** 20 * {@code AccessPermission} adjusts the access permissions of members like methods 21 * and properties in a specific context. 22 * 23 * <p>You can hide methods from for..in loops and protect them from deletion and 24 * from being overwritten. 25 * 26 * <p>Note that no matter what access permissions you set they can be overwritten. 27 * 28 * <p>Also note that the access permissions are not applied to the object but to 29 * the reference to the object. That means that the object can for example be 30 * enumerable in one reference but not in another. 31 * 32 * <p>Example: 33 * <code> 34 * var object:Object = new Object(); 35 * object.myProperty = new Object(); 36 * object.mySecondReference = object.myProperty; 37 * trace("myProperty: Value: " + object.myProperty); 38 * trace("mySecondReference: Value: " + object.mySecondReference); 39 * AccessPermission.set(object, ["myProperty"], AccessPermission.PROTECT_DELETE); 40 * trace("myProperty: Permission: " + AccessPermission.get(object, "myProperty")); 41 * trace("mySecondReference: Permission: " + AccessPermission.get(object, "mySecondReference")); 42 * delete object.myProperty; 43 * delete object.mySecondReference; 44 * trace("myProperty: Value: " + object.myProperty); 45 * trace("mySecondReference: Value: " + object.mySecondReference); 46 * </code> 47 * 48 * <p>Output: 49 * <pre> 50 * myProperty: Value: [object Object] 51 * mySecondReference: Value: [object Object] 52 * myProperty: Permission: 2 53 * mySecondReference: Permission: 0 54 * myProperty: Value: [object Object] 55 * mySecondReference: Value: undefined 56 * </pre> 57 * 58 * <p>As you can see, the above statement holds true. We have two references that 59 * reference the same object. We set the access permission of one reference. We can 60 * then not delete the reference the access permission was applied to, but the other 61 * reference. 62 * 63 * <p>Following is another example with a property in its normal state and another 64 * protected property we applied the {@link #ALLOW_NOTHING} access permission to. 65 * 66 * <p>Example: 67 * <code> 68 * var object:Object = new Object(); 69 * object.myNormalProperty = "myNormalPropertyValue"; 70 * object.myProtectedProperty = "myProtectedPropertyValue"; 71 * trace("myNormalProperty: Default Permission: " + AccessPermission.get(object, "myNormalProperty")); 72 * trace("myProtectedProperty: Default Permission: " + AccessPermission.get(object, "myProtectedProperty")); 73 * AccessPermission.set(object, ["myProtectedProperty"], AccessPermission.ALLOW_NOTHING); 74 * trace("myProtectedProperty: New Permission: " + AccessPermission.get(object, "myProtectedProperty")); 75 * object.myNormalProperty = "newMyNormalPropertyValue"; 76 * object.myProtectedProperty = "newMyProtectedPropertyValue"; 77 * trace("myNormalProperty: Value After Overwriting: " + object.myNormalProperty); 78 * trace("myProtectedProperty: Value After Overwriting: " + object.myProtectedProperty); 79 * for (var i:String in object) { 80 * trace(i + ": Found In For..In Loop, Value: " + object[i]); 81 * } 82 * delete object.myNormalProperty; 83 * delete object.myProtectedProperty; 84 * trace("myNormalProperty: Value After Deletion: " + object.myNormalProperty); 85 * trace("myProtectedProperty: Value After Deletion: " + object.myProtectedProperty); 86 * </code> 87 * 88 * <p>Output: 89 * <pre> 90 * myNormalProperty: Default Permission: 0 91 * myProtectedProperty: Default Permission: 0 92 * myProtectedProperty: New Permission: 7 93 * myNormalProperty: Value After Overwriting: newMyNormalPropertyValue 94 * myProtectedProperty: Value After Overwriting: myProtectedPropertyValue 95 * myNormalProperty: Found In For..In Loop, Value: newMyNormalPropertyValue 96 * myNormalProperty: Value After Deletion: undefined 97 * myProtectedProperty: Value After Deletion: myProtectedPropertyValue 98 * </pre> 99 * 100 * <p>As you can see the protected property cannot be deleted, overwritten and is 101 * hidden from for..in loops, while the non-protected property can be deleted, can 102 * be overwritten and can be enumerated. 103 * 104 * <p>Besides the {@link #get} method you can check up on properties for specific 105 * access permissions using the {@link #isEnumerable}, {@link #isDeletable} and 106 * {@link #isOverwritable} methods. 107 * 108 * @author Simon Wacker 109 */ 110 class org.as2lib.util.AccessPermission extends BasicClass { 111 112 /** 113 * Allow everything to be done with the object. 114 */ 115 public static var ALLOW_ALL:Number = 0; 116 117 /** 118 * Hide an object from for..in loops. 119 */ 120 public static var HIDE:Number = 1; 121 122 /** 123 * Protect an object from deletion. 124 */ 125 public static var PROTECT_DELETE:Number = 2; 126 127 /** 128 * Protect an object from overwriting. 129 */ 130 public static var PROTECT_OVERWRITE:Number = 4; 131 132 /** 133 * Allow nothing to be done with the object. 134 */ 135 public static var ALLOW_NOTHING:Number = 7; 136 137 /** 138 * Sets the access permission of a reference by an access code. 139 * 140 * <p>The following access codes are applicable: 141 * <table> 142 * <tr> 143 * <th>{@link #HIDE}</th> 144 * <td>Hides the reference from for-in loops.</td> 145 * </tr> 146 * <tr> 147 * <th>{@link #PROTECT_DELETE}</th> 148 * <td>Protects the reference from deletion</td> 149 * </tr> 150 * <tr> 151 * <th>{@link #PROTECT_OVERWRITE}</th> 152 * <td>Protects the reference from overwriting</td> 153 * </tr> 154 * <tr> 155 * <th>{@link #ALLOW_ALL}</th> 156 * <td>Allows everything to be done with the reference.</td> 157 * </tr> 158 * <tr> 159 * <th>{@link #ALLOW_NOTHING}</th> 160 * <td>Allows nothing to be done with the reference.</td> 161 * </tr> 162 * </table> 163 * 164 * <p>These access codes can be combined as follows to apply multiple access 165 * permissions. 166 * <code> 167 * AccessPermission.PROTECT_DELETE | AccessPermission.PROTECT_OVERWRITE 168 * </code> 169 * 170 * <p>Note that every new invocation of this method simply overwrites the old access 171 * permissions of the reference. 172 * 173 * @param target the object that holds references to the objects the access permissions 174 * shall be applied to 175 * @param referenceNames the names of the references to apply the access permission to 176 * @param access the access permissions to apply 177 */ 178 public static function set(target, referenceNames:Array, access:Number):Void { 179 _global.ASSetPropFlags(target, referenceNames, access, true); 180 } 181 182 /** 183 * Returns the current access permission of the reference. 184 * 185 * <p>The permission is represented by a {@code Number}. This number is a bitwise 186 * combination of the three access specifier {@link #HIDE}, {@link #PROTECT_DELETE} 187 * and {@link #PROTECT_OVERWRITE}. You can find out what the returned access 188 * permission number means using these constants. 189 * 190 * @param target the target object that holds the reference 191 * @param referenceName the name of the reference to return the access permission for 192 * @return a number representing the access permission of the reference 193 */ 194 public static function get(target, referenceName:String):Number { 195 var result:Number = 0; 196 if (!isEnumerable(target, referenceName)) result |= HIDE; 197 if (!isOverwritable(target, referenceName)) result |= PROTECT_OVERWRITE; 198 if (!isDeletable(target, referenceName)) result |= PROTECT_DELETE; 199 return result; 200 } 201 202 /** 203 * Returns whether the reference is enumerable. 204 * 205 * @param target the target object that holds the reference 206 * @param referenceName the name of the reference to return whether it is enumerable 207 * @return {@code true} if the reference is enumerable else {@code false} 208 * @link http://chattyfig.figleaf.com/flashcoders-wiki/index.php?ASSetPropFlags 209 */ 210 public static function isEnumerable(target, referenceName:String):Boolean { 211 // Why not use target.isPropertyEnumerable(referenceName)? 212 for (var i:String in target){ 213 if (i == referenceName) return true; 214 } 215 return false; 216 } 217 218 /** 219 * Returns whether the reference is overwritable. 220 * 221 * @param target the target object that holds the reference 222 * @param referenceName the name of the reference to return whether it is overwritable 223 * @return {@code true} if the reference is overwritable else {@code false} 224 * @link http://chattyfig.figleaf.com/flashcoders-wiki/index.php?ASSetPropFlags 225 */ 226 public static function isOverwritable(target, referenceName:String):Boolean { 227 var tmp = target[referenceName]; 228 var newVal = (tmp == 0) ? 1 : 0; 229 target[referenceName] = newVal; 230 if(target[referenceName] == newVal){ 231 target[referenceName] = tmp; 232 return true; 233 }else{ 234 return false; 235 } 236 } 237 238 /** 239 * Returns whether the reference is deletable. 240 * 241 * @param target the target object that holds the reference 242 * @param referenceName the name of the reference to return whether it is deletable 243 * @return {@code true} if the reference is deletable else {@code false} 244 * @link http://chattyfig.figleaf.com/flashcoders-wiki/index.php?ASSetPropFlags 245 */ 246 public static function isDeletable(target, referenceName:String):Boolean { 247 var tmp = target[referenceName]; 248 if (tmp === undefined) return false; 249 var enumerable:Boolean = isEnumerable(target, referenceName); 250 delete target[referenceName]; 251 if(target[referenceName] === undefined){ 252 target[referenceName] = tmp; 253 _global.ASSetPropFlags(target, referenceName, !enumerable, 1); 254 return true; 255 } 256 return false; 257 } 258 259 /** 260 * Private constructor. 261 */ 262 private function AccessPermission(Void) { 263 } 264 265 }