diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/GTD-Cryptocurrency-1.0.1.changelog.txt b/GTD-Cryptocurrency-1.0.1.changelog.txt new file mode 100644 index 0000000..ea8643a --- /dev/null +++ b/GTD-Cryptocurrency-1.0.1.changelog.txt @@ -0,0 +1,17 @@ +Release 1.0.1 + +https://bitbucket.org/JeanLucPicard/nxt/downloads/GTD-Cryptocurrency-1.0.1.exe + +sha256: + +75d7efaf624b01af512a6d4e93a3dc5fa55942d2e5561b892218897c053eaf78 *GTD-Cryptocurrency-1.0.1.exe +https://bitbucket.org/JeanLucPicard/nxt/downloads/GTD-Cryptocurrency-1.0.1.jar + +sha256: + +f27abd10f830f8d99fea050a13353f2dce39b8f46d5e076304285c2fcd8c97c1 *GTD-Cryptocurrency-1.0.1.jar + + +Change log: + + diff --git a/GTD-Cryptocurrency.exe b/GTD-Cryptocurrency.exe new file mode 100644 index 0000000..421f188 Binary files /dev/null and b/GTD-Cryptocurrency.exe differ diff --git a/GTD-Cryptocurrency.jar b/GTD-Cryptocurrency.jar deleted file mode 100644 index 5e9f808..0000000 Binary files a/GTD-Cryptocurrency.jar and /dev/null differ diff --git a/GTD-Cryptocurrencyservice.exe b/GTD-Cryptocurrencyservice.exe new file mode 100644 index 0000000..421f188 Binary files /dev/null and b/GTD-Cryptocurrencyservice.exe differ diff --git a/conf/nxt-default.properties b/conf/nxt-default.properties index 62750c7..244d33f 100644 --- a/conf/nxt-default.properties +++ b/conf/nxt-default.properties @@ -15,7 +15,7 @@ ################################################################################ # Do not modify this file. Instead, create a nxt.properties file with only the -# properties you need to change, and set them there. The values in +# properties you need to change, and set them there. The values in # nxt.properties override those in nxt-default.properties. @@ -36,7 +36,7 @@ nxt.shareMyAddress=true # Port for incoming peer to peer networking requests, if enabled. -nxt.peerServerPort=47874 +nxt.peerServerPort=37874 # Enable UPnP for the peer port. nxt.enablePeerUPnP=true @@ -67,7 +67,7 @@ nxt.myHallmark= # Default initial peers. Only used if nxt.usePeersDb=true. # Do not modify. Add custom peers to nxt.wellKnownPeers instead. -nxt.defaultPeers= +nxt.defaultPeers=193.70.91.232; 35.182.246.236; # A list of well known peer addresses / host names, separated by '; '. These # peers are always kept in connected state. @@ -159,7 +159,7 @@ nxt.getMorePeers=true # Set to true to run offline - do not connect to peers and do not listen for # incoming peer connections. This is equivalent to setting -# nxt.shareMyAddress=false, nxt.wellKnownPeers=, nxt.testnetPeers= +# nxt.shareMyAddress=false, nxt.wellKnownPeers=, nxt.testnetPeers= # and nxt.usePeersDb=false, and if set to true overrides those properties. nxt.isOffline=false @@ -186,11 +186,11 @@ nxt.enableAPIServer=true nxt.allowedBotHosts=127.0.0.1; localhost; [0:0:0:0:0:0:0:1]; # Port for http/json API requests. -nxt.apiServerPort=7876 +nxt.apiServerPort=37876 # Port for https/json API request. If same as nxt.apiServerPort, the nxt.apiSSL # setting determines whether SSL is used or not. -nxt.apiServerSSLPort=7876 +nxt.apiServerSSLPort=37876 # Enable UPnP for the API ports. nxt.enableAPIUPnP=false @@ -245,7 +245,7 @@ nxt.apiServerEnforcePOST=true # requests. # Please choose a decent password here. Preferably, use a password generator. # Password protection is disabled and password is not needed when the API server -# only listens on the localhost interface, i.e. when +# only listens on the localhost interface, i.e. when # nxt.apiServerHost=127.0.0.1. nxt.adminPassword= @@ -657,4 +657,3 @@ nxt.disableSecurityPolicy=false # NRS version. nxt.version=1.11.13 - diff --git a/h2.sh b/h2.sh new file mode 100644 index 0000000..1244ce9 --- /dev/null +++ b/h2.sh @@ -0,0 +1,2 @@ +#!/bin/sh +java -cp lib/h2*.jar org.h2.tools.Shell -url jdbc:h2:./nxt_db/nxt -user sa -password sa diff --git a/html/www/icon.ico b/html/www/icon.ico new file mode 100644 index 0000000..7c84d59 Binary files /dev/null and b/html/www/icon.ico differ diff --git a/html/www/img/installer_left_pane.png b/html/www/img/installer_left_pane.png new file mode 100644 index 0000000..796065b Binary files /dev/null and b/html/www/img/installer_left_pane.png differ diff --git a/installer/.gitignore b/installer/.gitignore new file mode 100644 index 0000000..397b4a7 --- /dev/null +++ b/installer/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/installer/AppIcon.icns b/installer/AppIcon.icns new file mode 100644 index 0000000..fe3a292 Binary files /dev/null and b/installer/AppIcon.icns differ diff --git a/installer/RegistrySpec.xml b/installer/RegistrySpec.xml new file mode 100644 index 0000000..b8a00c6 --- /dev/null +++ b/installer/RegistrySpec.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + diff --git a/installer/Unix_shortcutSpec.xml b/installer/Unix_shortcutSpec.xml new file mode 100644 index 0000000..395d3ae --- /dev/null +++ b/installer/Unix_shortcutSpec.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + diff --git a/installer/build-exe.bat b/installer/build-exe.bat new file mode 100644 index 0000000..300b7ba --- /dev/null +++ b/installer/build-exe.bat @@ -0,0 +1,2 @@ +@echo off +..\installer\lib\izpack2exe\izpack2exe.py --file ..\%1.jar --output ..\%1.exe --with-7z=..\installer\lib\izpack2exe\7za.exe --no-upx --with-jdk=..\jre --name nxt > ..\installer\build-exe.log 2>&1 \ No newline at end of file diff --git a/installer/build-installer.sh b/installer/build-installer.sh new file mode 100644 index 0000000..92b9b22 --- /dev/null +++ b/installer/build-installer.sh @@ -0,0 +1,2 @@ +#!/bin/sh +java -Xmx512m -cp "../installer/lib/*" com.izforge.izpack.compiler.bootstrap.CompilerLauncher ../installer/setup.xml -o $1.jar > ../installer/build-installer.log 2>&1 \ No newline at end of file diff --git a/installer/build-readme.txt b/installer/build-readme.txt new file mode 100644 index 0000000..6d0e545 --- /dev/null +++ b/installer/build-readme.txt @@ -0,0 +1,44 @@ +Building the NXT installer + +Note: all pathes are relative to the git repository folder (nxt-private) + +Pre-requisites for both Unix and Windows +======================================== +Compile classes on Unix using compile.sh +Windows build has to be executed from a Cygwin shell (Install from https://www.cygwin.com/) +Compile classes on Windows by running win-compile.sh from a Cygwin shell +In order to create an obfuscated release also install proguard (http://proguard.sourceforge.net/) +Package NXT.jar using jar.sh +mkdir jre + +Building the installer on Unix +============================== +Execute the build: ./release-package.sh +Review results: vi installer/build-installer.log +Test X11 installer: java -jar nxt-client-.jar +Test console installer: java -jar nxt-client-.jar -console + +Building the installer on Windows +================================= +Initial setup (perform once for each development workstation or whenever Java is updated) +Install the latest version of the Java Windows Server JRE (64 bit) +Copy the content of Java JRE folder (C:\Program Files\Java\jre) into the jre folder under your nxt-private git repository preserving the folder structure +Install the latest Java JDK x64 for Windows - needed for the jar and jarsigner commands +Install python and associate it with .py file extension - required by build-exe.bat +Install the Microsoft Windows SDK for Windows 7 and .NET Framework 4, make sure the signtool.exe command is in your path - needed to sign the installer executable + +From a Cygwin shell invoke the command win-release-package.sh followed by the version number +Review results in installer/build-installer.log, installer/build-exe.log +Digitally sign the installer jar file and zip file using jarsigner +Digitally sign the installer exe file using signtool +Test the installer using Java: java -jar nxt-client-.jar +Test the windows executable: nxt-client-.exe + +Technical information +===================== +Installer is based on the IzPack product from http://izpack.org/ +Installer project source code is in installer/setup.xml, RegistrySpec.xml and shortcutSpec.xml +nxt.jar is now self executing, the full classpath is embedded into the jar file manifest automatically by jar.sh +Converting the Jar file to a Windows exe relies on the 7za utility (http://www.7-zip.org/) bundled with the IzPack distribution +Creating and signing the installer jar can be performed either on Unix or Windows +Creating and signing the installer exe must be performed on a Windows workstation \ No newline at end of file diff --git a/installer/lib/JavaExe.exe b/installer/lib/JavaExe.exe new file mode 100644 index 0000000..421f188 Binary files /dev/null and b/installer/lib/JavaExe.exe differ diff --git a/installer/lib/ant-1.9.4.jar b/installer/lib/ant-1.9.4.jar new file mode 100644 index 0000000..24641e7 Binary files /dev/null and b/installer/lib/ant-1.9.4.jar differ diff --git a/installer/lib/ant-launcher-1.9.4.jar b/installer/lib/ant-launcher-1.9.4.jar new file mode 100644 index 0000000..97c2262 Binary files /dev/null and b/installer/lib/ant-launcher-1.9.4.jar differ diff --git a/installer/lib/asm-all-2.2.3.jar b/installer/lib/asm-all-2.2.3.jar new file mode 100644 index 0000000..7a1f2fa Binary files /dev/null and b/installer/lib/asm-all-2.2.3.jar differ diff --git a/installer/lib/bcel-5.2.jar b/installer/lib/bcel-5.2.jar new file mode 100644 index 0000000..2fa90ce Binary files /dev/null and b/installer/lib/bcel-5.2.jar differ diff --git a/installer/lib/classworlds-1.1-alpha-2.jar b/installer/lib/classworlds-1.1-alpha-2.jar new file mode 100644 index 0000000..1208b48 Binary files /dev/null and b/installer/lib/classworlds-1.1-alpha-2.jar differ diff --git a/installer/lib/commons-cli-1.2.jar b/installer/lib/commons-cli-1.2.jar new file mode 100644 index 0000000..ce4b9ff Binary files /dev/null and b/installer/lib/commons-cli-1.2.jar differ diff --git a/installer/lib/commons-collections-3.1.jar b/installer/lib/commons-collections-3.1.jar new file mode 100644 index 0000000..41e230f Binary files /dev/null and b/installer/lib/commons-collections-3.1.jar differ diff --git a/installer/lib/commons-compress-1.3.jar b/installer/lib/commons-compress-1.3.jar new file mode 100644 index 0000000..6c826c5 Binary files /dev/null and b/installer/lib/commons-compress-1.3.jar differ diff --git a/installer/lib/commons-io-2.4.jar b/installer/lib/commons-io-2.4.jar new file mode 100644 index 0000000..90035a4 Binary files /dev/null and b/installer/lib/commons-io-2.4.jar differ diff --git a/installer/lib/commons-lang-2.6.jar b/installer/lib/commons-lang-2.6.jar new file mode 100644 index 0000000..98467d3 Binary files /dev/null and b/installer/lib/commons-lang-2.6.jar differ diff --git a/installer/lib/izpack-ant-5.0.5.jar b/installer/lib/izpack-ant-5.0.5.jar new file mode 100644 index 0000000..08978c0 Binary files /dev/null and b/installer/lib/izpack-ant-5.0.5.jar differ diff --git a/installer/lib/izpack-api-5.0.5.jar b/installer/lib/izpack-api-5.0.5.jar new file mode 100644 index 0000000..1b69d69 Binary files /dev/null and b/installer/lib/izpack-api-5.0.5.jar differ diff --git a/installer/lib/izpack-compiler-5.0.5.jar b/installer/lib/izpack-compiler-5.0.5.jar new file mode 100644 index 0000000..8179b74 Binary files /dev/null and b/installer/lib/izpack-compiler-5.0.5.jar differ diff --git a/installer/lib/izpack-core-5.0.5.jar b/installer/lib/izpack-core-5.0.5.jar new file mode 100644 index 0000000..ecb1d90 Binary files /dev/null and b/installer/lib/izpack-core-5.0.5.jar differ diff --git a/installer/lib/izpack-event-5.0.5.jar b/installer/lib/izpack-event-5.0.5.jar new file mode 100644 index 0000000..3cfb13d Binary files /dev/null and b/installer/lib/izpack-event-5.0.5.jar differ diff --git a/installer/lib/izpack-gui-5.0.5.jar b/installer/lib/izpack-gui-5.0.5.jar new file mode 100644 index 0000000..71f111e Binary files /dev/null and b/installer/lib/izpack-gui-5.0.5.jar differ diff --git a/installer/lib/izpack-installer-5.0.5.jar b/installer/lib/izpack-installer-5.0.5.jar new file mode 100644 index 0000000..22d3c43 Binary files /dev/null and b/installer/lib/izpack-installer-5.0.5.jar differ diff --git a/installer/lib/izpack-native-5.0.5.jar b/installer/lib/izpack-native-5.0.5.jar new file mode 100644 index 0000000..6e917fb Binary files /dev/null and b/installer/lib/izpack-native-5.0.5.jar differ diff --git a/installer/lib/izpack-panel-5.0.5.jar b/installer/lib/izpack-panel-5.0.5.jar new file mode 100644 index 0000000..5678491 Binary files /dev/null and b/installer/lib/izpack-panel-5.0.5.jar differ diff --git a/installer/lib/izpack-tools-5.0.5.jar b/installer/lib/izpack-tools-5.0.5.jar new file mode 100644 index 0000000..1941867 Binary files /dev/null and b/installer/lib/izpack-tools-5.0.5.jar differ diff --git a/installer/lib/izpack-uninstaller-5.0.5.jar b/installer/lib/izpack-uninstaller-5.0.5.jar new file mode 100644 index 0000000..35c9b91 Binary files /dev/null and b/installer/lib/izpack-uninstaller-5.0.5.jar differ diff --git a/installer/lib/izpack-util-5.0.5.jar b/installer/lib/izpack-util-5.0.5.jar new file mode 100644 index 0000000..ed428a6 Binary files /dev/null and b/installer/lib/izpack-util-5.0.5.jar differ diff --git a/installer/lib/izpack2exe/7zS.sfx b/installer/lib/izpack2exe/7zS.sfx new file mode 100644 index 0000000..0cfaf3e Binary files /dev/null and b/installer/lib/izpack2exe/7zS.sfx differ diff --git a/installer/lib/izpack2exe/7za b/installer/lib/izpack2exe/7za new file mode 100644 index 0000000..35cb4f5 Binary files /dev/null and b/installer/lib/izpack2exe/7za differ diff --git a/installer/lib/izpack2exe/7za.exe b/installer/lib/izpack2exe/7za.exe new file mode 100644 index 0000000..06e8b43 Binary files /dev/null and b/installer/lib/izpack2exe/7za.exe differ diff --git a/installer/lib/izpack2exe/LICENSE.7zip.txt b/installer/lib/izpack2exe/LICENSE.7zip.txt new file mode 100644 index 0000000..4c38901 --- /dev/null +++ b/installer/lib/izpack2exe/LICENSE.7zip.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/installer/lib/izpack2exe/LICENSE.txt b/installer/lib/izpack2exe/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/installer/lib/izpack2exe/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/installer/lib/izpack2exe/LICENSE.upx.txt b/installer/lib/izpack2exe/LICENSE.upx.txt new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/installer/lib/izpack2exe/LICENSE.upx.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/installer/lib/izpack2exe/NOTICE b/installer/lib/izpack2exe/NOTICE new file mode 100644 index 0000000..c0c494d --- /dev/null +++ b/installer/lib/izpack2exe/NOTICE @@ -0,0 +1,7 @@ +IzPack notice +------------- + + This product includes software developed by Julien Ponge and others + for the IzPack project: + - http://izpack.org/ + - http://izpack.codehaus.org/ diff --git a/installer/lib/izpack2exe/app.ico b/installer/lib/izpack2exe/app.ico new file mode 100644 index 0000000..38ab95a Binary files /dev/null and b/installer/lib/izpack2exe/app.ico differ diff --git a/installer/lib/izpack2exe/exe.ico b/installer/lib/izpack2exe/exe.ico new file mode 100644 index 0000000..0ab0ce3 Binary files /dev/null and b/installer/lib/izpack2exe/exe.ico differ diff --git a/installer/lib/izpack2exe/izpack2exe.py b/installer/lib/izpack2exe/izpack2exe.py new file mode 100644 index 0000000..918d669 --- /dev/null +++ b/installer/lib/izpack2exe/izpack2exe.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +# ........................................................................... # +# +# IzPack - Copyright 2007, 2010 Julien Ponge, All Rights Reserved. +# +# http://izpack.org/ +# http://izpack.codehaus.org/ +# +# Licensed 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. +# ........................................................................... # + +import os +import sys +import subprocess +import shutil +import optparse + +def parse_options(): + parser = optparse.OptionParser() + parser.add_option("--file", action="append", dest="file", + help="The installer JAR file / files") + parser.add_option("--output", action="store", dest="output", + default="setup.exe", + help="The executable file") + parser.add_option("--with-jdk", action="store", dest="with_jre", default="", + help="The bundled JRE to run the exe independently of the system resources. ") # choosen JDK that may came with the package + parser.add_option("--with-7z", action="store", dest="p7z", + default="7za", + help="Path to the 7-Zip executable") + parser.add_option("--with-upx", action="store", dest="upx", + default="upx", + help="Path to the UPX executable") + parser.add_option("--no-upx", action="store_true", dest="no_upx", + default=False, + help="Do not use UPX to further compress the output") + parser.add_option("--launch-file", action="store", dest="launch", + default="", + help="File to launch after extract") + parser.add_option("--launch-args", action="store", dest="launchargs", + default="", + help="Arguments for file to launch after extract") + parser.add_option("--name", action="store", dest="name", + default="IzPack", + help="Name of package for title bar and prompts") + parser.add_option("--prompt", action="store_true", dest="prompt", + default=False, + help="Prompt the user before extraction?") + (options, args) = parser.parse_args() + if (options.file is None): + parser.error("no installer file has been given") + return options + +def create_exe(settings): + if len(settings.file) > 0: + filename = os.path.basename(settings.file[0]) + else: + filename = '' + + if len(settings.with_jre) > 0: + jdk = os.path.basename(settings.with_jre) #inside the jdk/jre that was given, there must be a bin/java.exe file + jdk = jdk + "\\bin\\javaw.exe" + print(jdk) + settings.file.append(settings.with_jre) #jdk/jre is going in the package + else: + jdk = 'javaw' #java is added somehow to the PATH + + if settings.p7z == '7za': + p7z = os.path.join(os.path.dirname(sys.argv[0]), '7za') + else: + p7z = settings.p7z + + use_shell = sys.platform != 'win32' + + if (os.access('installer.7z', os.F_OK)): + os.remove('installer.7z') + files = '" "'.join(settings.file) + p7zcmd = '"%s" a -mmt -t7z -mx=9 installer.7z "%s"' % (p7z, files) + print(p7zcmd) + subprocess.call(p7zcmd, shell=use_shell) + + config = open('config.txt', 'w') + config.write(';!@Install@!UTF-8!\n') + config.write('Title="%s"\n' % settings.name) + if settings.prompt: + config.write('BeginPrompt="Install %s?"\n' % settings.name) + config.write('Progress="yes"\n') + + if settings.launch == '': + config.write('ExecuteFile="' + jdk +'"\n') # who is going to run my installer.jar? + config.write('ExecuteParameters="-jar \\\"%s\\\"' % filename) + if settings.launchargs != '': + config.write(' %s"\n' % settings.launchargs) + else: + config.write('"\n') + else: + config.write('ExecuteFile="%s"\n' % settings.launch) + if settings.launchargs != '': + config.write('ExecuteParameters="%s"\n' % settings.launchargs) + + config.write(';!@InstallEnd@!\n') + config.close() + + sfx = os.path.join(os.path.dirname(p7z), '7zS.sfx') + files = [sfx, 'config.txt', 'installer.7z'] + + output = open(settings.output, 'wb') + for f in files: + in_file = open(f, 'rb') + shutil.copyfileobj(in_file, output, 2048) + in_file.close() + output.close() + + if (not settings.no_upx): + if settings.upx == 'upx': + upx = os.path.join(os.path.dirname(sys.argv[0]), 'upx') + else: + upx = settings.upx + upx = '"%s" --ultra-brute "%s"' % (upx, settings.output) + subprocess.call(upx, shell=use_shell) + + os.remove('config.txt') + os.remove('installer.7z') + +def main(): + create_exe(parse_options()) + +if __name__ == "__main__": + main() diff --git a/installer/lib/izpack2exe/setup.py b/installer/lib/izpack2exe/setup.py new file mode 100644 index 0000000..a2a5035 --- /dev/null +++ b/installer/lib/izpack2exe/setup.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# ........................................................................... # +# +# IzPack - Copyright 2007, 2008 Julien Ponge, All Rights Reserved. +# +# http://izpack.org/ +# http://izpack.codehaus.org/ +# +# Licensed 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. +# ........................................................................... # + +from distutils.core import setup +import py2exe + +setup( + console = [{ + 'script': 'izpack2exe.py', + 'icon_resources': [(0, 'app.ico')] + }], + script_args=['py2exe', '--bundle-files', '1'] +) diff --git a/installer/lib/izpack2exe/upx b/installer/lib/izpack2exe/upx new file mode 100644 index 0000000..2a0b318 Binary files /dev/null and b/installer/lib/izpack2exe/upx differ diff --git a/installer/lib/izpack2exe/upx.exe b/installer/lib/izpack2exe/upx.exe new file mode 100644 index 0000000..6266213 Binary files /dev/null and b/installer/lib/izpack2exe/upx.exe differ diff --git a/installer/lib/jakarta-regexp-1.4.jar b/installer/lib/jakarta-regexp-1.4.jar new file mode 100644 index 0000000..5d70c35 Binary files /dev/null and b/installer/lib/jakarta-regexp-1.4.jar differ diff --git a/installer/lib/jdom2-2.0.5.jar b/installer/lib/jdom2-2.0.5.jar new file mode 100644 index 0000000..b6996c7 Binary files /dev/null and b/installer/lib/jdom2-2.0.5.jar differ diff --git a/installer/lib/jline-2.12.jar b/installer/lib/jline-2.12.jar new file mode 100644 index 0000000..41676a1 Binary files /dev/null and b/installer/lib/jline-2.12.jar differ diff --git a/installer/lib/kunstoff-laf-2.0.2.jar b/installer/lib/kunstoff-laf-2.0.2.jar new file mode 100644 index 0000000..dbdc05d Binary files /dev/null and b/installer/lib/kunstoff-laf-2.0.2.jar differ diff --git a/installer/lib/kunststoff.jar b/installer/lib/kunststoff.jar new file mode 100644 index 0000000..8e06bb6 Binary files /dev/null and b/installer/lib/kunststoff.jar differ diff --git a/installer/lib/laf-plugin-1.1.jar b/installer/lib/laf-plugin-1.1.jar new file mode 100644 index 0000000..a1be3ee Binary files /dev/null and b/installer/lib/laf-plugin-1.1.jar differ diff --git a/installer/lib/laf-widget-5.0.jar b/installer/lib/laf-widget-5.0.jar new file mode 100644 index 0000000..e5394bb Binary files /dev/null and b/installer/lib/laf-widget-5.0.jar differ diff --git a/installer/lib/liquidlnf.jar b/installer/lib/liquidlnf.jar new file mode 100644 index 0000000..8049772 Binary files /dev/null and b/installer/lib/liquidlnf.jar differ diff --git a/installer/lib/lite-2.2.3.jar b/installer/lib/lite-2.2.3.jar new file mode 100644 index 0000000..3d2401c Binary files /dev/null and b/installer/lib/lite-2.2.3.jar differ diff --git a/installer/lib/looks-2.2.2.jar b/installer/lib/looks-2.2.2.jar new file mode 100644 index 0000000..ef571d4 Binary files /dev/null and b/installer/lib/looks-2.2.2.jar differ diff --git a/installer/lib/looks.jar b/installer/lib/looks.jar new file mode 100644 index 0000000..2695857 Binary files /dev/null and b/installer/lib/looks.jar differ diff --git a/installer/lib/maven-artifact-2.2.1.jar b/installer/lib/maven-artifact-2.2.1.jar new file mode 100644 index 0000000..abab479 Binary files /dev/null and b/installer/lib/maven-artifact-2.2.1.jar differ diff --git a/installer/lib/maven-model-2.2.1.jar b/installer/lib/maven-model-2.2.1.jar new file mode 100644 index 0000000..73175f8 Binary files /dev/null and b/installer/lib/maven-model-2.2.1.jar differ diff --git a/installer/lib/maven-shared-jar-1.1.jar b/installer/lib/maven-shared-jar-1.1.jar new file mode 100644 index 0000000..2ad4f3d Binary files /dev/null and b/installer/lib/maven-shared-jar-1.1.jar differ diff --git a/installer/lib/metouia.jar b/installer/lib/metouia.jar new file mode 100644 index 0000000..2b23a58 Binary files /dev/null and b/installer/lib/metouia.jar differ diff --git a/installer/lib/picocontainer-2.14.1.jar b/installer/lib/picocontainer-2.14.1.jar new file mode 100644 index 0000000..bf1df09 Binary files /dev/null and b/installer/lib/picocontainer-2.14.1.jar differ diff --git a/installer/lib/plexus-container-default-1.0-alpha-9-stable-1.jar b/installer/lib/plexus-container-default-1.0-alpha-9-stable-1.jar new file mode 100644 index 0000000..a09f890 Binary files /dev/null and b/installer/lib/plexus-container-default-1.0-alpha-9-stable-1.jar differ diff --git a/installer/lib/plexus-digest-1.0.jar b/installer/lib/plexus-digest-1.0.jar new file mode 100644 index 0000000..d7eda22 Binary files /dev/null and b/installer/lib/plexus-digest-1.0.jar differ diff --git a/installer/lib/plexus-utils-1.5.1.jar b/installer/lib/plexus-utils-1.5.1.jar new file mode 100644 index 0000000..eddd858 Binary files /dev/null and b/installer/lib/plexus-utils-1.5.1.jar differ diff --git a/installer/lib/substance-6.0.jar b/installer/lib/substance-6.0.jar new file mode 100644 index 0000000..29e7ab8 Binary files /dev/null and b/installer/lib/substance-6.0.jar differ diff --git a/installer/lib/substance.jar b/installer/lib/substance.jar new file mode 100644 index 0000000..e370319 Binary files /dev/null and b/installer/lib/substance.jar differ diff --git a/installer/lib/trident-1.2.jar b/installer/lib/trident-1.2.jar new file mode 100644 index 0000000..fcefb2e Binary files /dev/null and b/installer/lib/trident-1.2.jar differ diff --git a/installer/lib/x86-3.3.0-v3346.jar b/installer/lib/x86-3.3.0-v3346.jar new file mode 100644 index 0000000..79e421a Binary files /dev/null and b/installer/lib/x86-3.3.0-v3346.jar differ diff --git a/installer/lib/xpp3-1.1.4c.jar b/installer/lib/xpp3-1.1.4c.jar new file mode 100644 index 0000000..451ac82 Binary files /dev/null and b/installer/lib/xpp3-1.1.4c.jar differ diff --git a/installer/setup.xml b/installer/setup.xml new file mode 100644 index 0000000..712e5dc --- /dev/null +++ b/installer/setup.xml @@ -0,0 +1,208 @@ + + + + + + + GTD + @{runtime.nxt.version} + https://gtd.network + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Common Server Files + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Windows Specific Resources + + + + + + + + + + + + + + Unix Specific Resources + + + + + + + + + + + + + + + + + + + + + + + + + + + + Java 64 bit for Windows + + + + + Mac Specific Resources + + + + + + + Java 64 bit for Mac + + + + + + diff --git a/installer/shortcutSpec.xml b/installer/shortcutSpec.xml new file mode 100644 index 0000000..8949f5a --- /dev/null +++ b/installer/shortcutSpec.xml @@ -0,0 +1,36 @@ + + + + + + + + + \ No newline at end of file diff --git a/mac-release-package.sh b/mac-release-package.sh new file mode 100644 index 0000000..fb4c402 --- /dev/null +++ b/mac-release-package.sh @@ -0,0 +1,72 @@ +#!/bin/bash +VERSION=$1 +if [ -x ${VERSION} ]; +then + echo VERSION not defined + exit 1 +fi +PACKAGE=nxt-client-${VERSION} +echo PACKAGE="${PACKAGE}" +CHANGELOG=nxt-client-${VERSION}.changelog.txt +OBFUSCATE=$2 +MACVERSION=$3 +if [ -x ${MACVERSION} ]; +then +MACVERSION=${VERSION} +fi +echo MACVERSION="${MACVERSION}" + +FILES="changelogs conf html lib resource contrib" +FILES="${FILES} nxt.exe nxtservice.exe" +FILES="${FILES} 3RD-PARTY-LICENSES.txt AUTHORS.txt LICENSE.txt" +FILES="${FILES} DEVELOPERS-GUIDE.md OPERATORS-GUIDE.md README.md README.txt USERS-GUIDE.md" +FILES="${FILES} mint.bat mint.sh run.bat run.sh run-tor.sh run-desktop.sh start.sh stop.sh compact.sh compact.bat sign.sh" +FILES="${FILES} nxt.policy nxtdesktop.policy NXT_Wallet.url Dockerfile" + +echo compile +./compile.sh +rm -rf html/doc/* +rm -rf nxt +rm -rf ${PACKAGE}.jar +rm -rf ${PACKAGE}.exe +rm -rf ${PACKAGE}.zip +mkdir -p nxt/ +mkdir -p nxt/logs +mkdir -p nxt/addons/src + +if [ "${OBFUSCATE}" = "obfuscate" ]; +then +echo obfuscate +~/proguard/proguard5.2.1/bin/proguard.sh @nxt.pro +mv ../nxt.map ../nxt.map.${VERSION} +else +FILES="${FILES} classes src COPYING.txt" +FILES="${FILES} compile.sh javadoc.sh jar.sh package.sh" +FILES="${FILES} win-compile.sh win-javadoc.sh win-package.sh" +echo javadoc +./javadoc.sh +fi +echo copy resources +cp installer/lib/JavaExe.exe nxt.exe +cp installer/lib/JavaExe.exe nxtservice.exe +cp -a ${FILES} nxt +cp -a logs/placeholder.txt nxt/logs +echo gzip +for f in `find nxt/html -name *.gz` +do + rm -f "$f" +done +for f in `find nxt/html -name *.html -o -name *.js -o -name *.css -o -name *.json -o -name *.ttf -o -name *.svg -o -name *.otf` +do + gzip -9c "$f" > "$f".gz +done +cd nxt +echo generate jar files +../jar.sh +echo package installer Jar +../installer/build-installer.sh ../${PACKAGE} +cd - +rm -rf nxt + +echo bundle a dmg file +/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/bin/javapackager -deploy -outdir . -outfile nxt-client -name nxt-installer -width 34 -height 43 -native dmg -srcfiles ${PACKAGE}.jar -appclass com.izforge.izpack.installer.bootstrap.Installer -v -Bmac.category=Business -Bmac.CFBundleIdentifier=org.nxt.client.installer -Bmac.CFBundleName=Nxt-Installer -Bmac.CFBundleVersion=${MACVERSION} -BappVersion=${MACVERSION} -Bicon=installer/AppIcon.icns -Bmac.signing-key-developer-id-app="Developer ID Application: Stichting NXT (YU63QW5EFW)" > installer/javapackager.log 2>&1 diff --git a/mobile/app/.gitignore b/mobile/app/.gitignore new file mode 100644 index 0000000..c7e6982 --- /dev/null +++ b/mobile/app/.gitignore @@ -0,0 +1 @@ +/wallet \ No newline at end of file diff --git a/mobile/app/createapp.bat b/mobile/app/createapp.bat new file mode 100644 index 0000000..4677614 --- /dev/null +++ b/mobile/app/createapp.bat @@ -0,0 +1,10 @@ +rmdir /s /q wallet +call cordova create wallet org.nxt.mobile.wallet "NXT Mobile Wallet" --template ..\..\html +cd wallet +rmdir /s /q icons +xcopy /y/i/s ..\..\icons icons +rmdir /s /q plugins +xcopy /y/i/s ..\..\plugins plugins +call cordova platform add android@6.1.2 +xcopy /y/i/s ..\..\platforms platforms +cd .. \ No newline at end of file diff --git a/mobile/app/createapp.sh b/mobile/app/createapp.sh new file mode 100644 index 0000000..4d073ff --- /dev/null +++ b/mobile/app/createapp.sh @@ -0,0 +1,18 @@ +#!/bin/sh +PLATFORM=$1 +if [ -x ${PLATFORM} ]; +then + echo PLATFORM not defined + exit 1 +fi +rm -rf wallet +cordova create wallet org.nxt.mobile.wallet "NXT Mobile Wallet" --template ../../html +cd wallet +rm -rf icons +rm -rf plugins +cp -a ../../icons icons +cp -a ../../plugins plugins +cordova platform add ${PLATFORM} +rm -rf platforms +cp -a ../../platforms platforms +cd .. diff --git a/mobile/app/runapp.bat b/mobile/app/runapp.bat new file mode 100644 index 0000000..4faabf1 --- /dev/null +++ b/mobile/app/runapp.bat @@ -0,0 +1,4 @@ +call updateapp.bat +cd wallet +call cordova run android +cd .. \ No newline at end of file diff --git a/mobile/app/runapp.sh b/mobile/app/runapp.sh new file mode 100644 index 0000000..09e4ea0 --- /dev/null +++ b/mobile/app/runapp.sh @@ -0,0 +1,11 @@ +#!/bin/sh +PLATFORM=$1 +if [ -x ${PLATFORM} ]; +then + echo PLATFORM not defined + exit 1 +fi +./updateapp.sh +cd wallet +cordova run ${PLATFORM} +cd .. diff --git a/mobile/app/updateapp.bat b/mobile/app/updateapp.bat new file mode 100644 index 0000000..940fccb --- /dev/null +++ b/mobile/app/updateapp.bat @@ -0,0 +1,4 @@ +cd wallet +rmdir /s /q www +xcopy /y/i/s ..\..\..\html\www www +cd .. \ No newline at end of file diff --git a/mobile/app/updateapp.sh b/mobile/app/updateapp.sh new file mode 100644 index 0000000..f375575 --- /dev/null +++ b/mobile/app/updateapp.sh @@ -0,0 +1,5 @@ +#!/bin/sh +cd wallet +rm -rf www +cp -a ../../../html/www www +cd .. diff --git a/mobile/icons/android/hdpi.png b/mobile/icons/android/hdpi.png new file mode 100644 index 0000000..9b1e172 Binary files /dev/null and b/mobile/icons/android/hdpi.png differ diff --git a/mobile/icons/android/ldpi.png b/mobile/icons/android/ldpi.png new file mode 100644 index 0000000..a17e3d3 Binary files /dev/null and b/mobile/icons/android/ldpi.png differ diff --git a/mobile/icons/android/mdpi.png b/mobile/icons/android/mdpi.png new file mode 100644 index 0000000..ce881da Binary files /dev/null and b/mobile/icons/android/mdpi.png differ diff --git a/mobile/icons/android/xhdpi.png b/mobile/icons/android/xhdpi.png new file mode 100644 index 0000000..b08238d Binary files /dev/null and b/mobile/icons/android/xhdpi.png differ diff --git a/mobile/icons/android/xxhdpi.png b/mobile/icons/android/xxhdpi.png new file mode 100644 index 0000000..599a101 Binary files /dev/null and b/mobile/icons/android/xxhdpi.png differ diff --git a/mobile/icons/android/xxxhdpi.png b/mobile/icons/android/xxxhdpi.png new file mode 100644 index 0000000..88936b7 Binary files /dev/null and b/mobile/icons/android/xxxhdpi.png differ diff --git a/mobile/icons/appstore/android/1024x500.png b/mobile/icons/appstore/android/1024x500.png new file mode 100644 index 0000000..97a8029 Binary files /dev/null and b/mobile/icons/appstore/android/1024x500.png differ diff --git a/mobile/icons/appstore/android/180x120.png b/mobile/icons/appstore/android/180x120.png new file mode 100644 index 0000000..2287043 Binary files /dev/null and b/mobile/icons/appstore/android/180x120.png differ diff --git a/mobile/icons/appstore/android/512.png b/mobile/icons/appstore/android/512.png new file mode 100644 index 0000000..b107d02 Binary files /dev/null and b/mobile/icons/appstore/android/512.png differ diff --git a/mobile/icons/appstore/ios/1024x1024-AppIcon.jpg b/mobile/icons/appstore/ios/1024x1024-AppIcon.jpg new file mode 100644 index 0000000..c042178 Binary files /dev/null and b/mobile/icons/appstore/ios/1024x1024-AppIcon.jpg differ diff --git a/mobile/icons/ios/icon-120.png b/mobile/icons/ios/icon-120.png new file mode 100644 index 0000000..a33614f Binary files /dev/null and b/mobile/icons/ios/icon-120.png differ diff --git a/mobile/icons/ios/icon-40.png b/mobile/icons/ios/icon-40.png new file mode 100644 index 0000000..92e0fdc Binary files /dev/null and b/mobile/icons/ios/icon-40.png differ diff --git a/mobile/icons/ios/icon-40@2x.png b/mobile/icons/ios/icon-40@2x.png new file mode 100644 index 0000000..6a0f330 Binary files /dev/null and b/mobile/icons/ios/icon-40@2x.png differ diff --git a/mobile/icons/ios/icon-40@3x.png b/mobile/icons/ios/icon-40@3x.png new file mode 100644 index 0000000..a33614f Binary files /dev/null and b/mobile/icons/ios/icon-40@3x.png differ diff --git a/mobile/icons/ios/icon-50.png b/mobile/icons/ios/icon-50.png new file mode 100644 index 0000000..c110a5f Binary files /dev/null and b/mobile/icons/ios/icon-50.png differ diff --git a/mobile/icons/ios/icon-50@2x.png b/mobile/icons/ios/icon-50@2x.png new file mode 100644 index 0000000..1eed8bc Binary files /dev/null and b/mobile/icons/ios/icon-50@2x.png differ diff --git a/mobile/icons/ios/icon-60.png b/mobile/icons/ios/icon-60.png new file mode 100644 index 0000000..4d11ae4 Binary files /dev/null and b/mobile/icons/ios/icon-60.png differ diff --git a/mobile/icons/ios/icon-60@2x.png b/mobile/icons/ios/icon-60@2x.png new file mode 100644 index 0000000..a33614f Binary files /dev/null and b/mobile/icons/ios/icon-60@2x.png differ diff --git a/mobile/icons/ios/icon-60@3x.png b/mobile/icons/ios/icon-60@3x.png new file mode 100644 index 0000000..5608caf Binary files /dev/null and b/mobile/icons/ios/icon-60@3x.png differ diff --git a/mobile/icons/ios/icon-72.png b/mobile/icons/ios/icon-72.png new file mode 100644 index 0000000..9b1e172 Binary files /dev/null and b/mobile/icons/ios/icon-72.png differ diff --git a/mobile/icons/ios/icon-72@2x.png b/mobile/icons/ios/icon-72@2x.png new file mode 100644 index 0000000..599a101 Binary files /dev/null and b/mobile/icons/ios/icon-72@2x.png differ diff --git a/mobile/icons/ios/icon-76.png b/mobile/icons/ios/icon-76.png new file mode 100644 index 0000000..34b567d Binary files /dev/null and b/mobile/icons/ios/icon-76.png differ diff --git a/mobile/icons/ios/icon-76@2x.png b/mobile/icons/ios/icon-76@2x.png new file mode 100644 index 0000000..41f31a9 Binary files /dev/null and b/mobile/icons/ios/icon-76@2x.png differ diff --git a/mobile/icons/ios/icon-835@2x.png b/mobile/icons/ios/icon-835@2x.png new file mode 100644 index 0000000..d95c16b Binary files /dev/null and b/mobile/icons/ios/icon-835@2x.png differ diff --git a/mobile/icons/ios/icon-small.png b/mobile/icons/ios/icon-small.png new file mode 100644 index 0000000..b3df8e8 Binary files /dev/null and b/mobile/icons/ios/icon-small.png differ diff --git a/mobile/icons/ios/icon-small@2x.png b/mobile/icons/ios/icon-small@2x.png new file mode 100644 index 0000000..a3e6871 Binary files /dev/null and b/mobile/icons/ios/icon-small@2x.png differ diff --git a/mobile/icons/ios/icon-small@3x.png b/mobile/icons/ios/icon-small@3x.png new file mode 100644 index 0000000..7bcd335 Binary files /dev/null and b/mobile/icons/ios/icon-small@3x.png differ diff --git a/mobile/icons/ios/icon.png b/mobile/icons/ios/icon.png new file mode 100644 index 0000000..5f23531 Binary files /dev/null and b/mobile/icons/ios/icon.png differ diff --git a/mobile/icons/ios/icon@2x.png b/mobile/icons/ios/icon@2x.png new file mode 100644 index 0000000..31cff83 Binary files /dev/null and b/mobile/icons/ios/icon@2x.png differ diff --git a/mobile/icons/screen/android/splash-land-hdpi.png b/mobile/icons/screen/android/splash-land-hdpi.png new file mode 100644 index 0000000..1ff5b6f Binary files /dev/null and b/mobile/icons/screen/android/splash-land-hdpi.png differ diff --git a/mobile/icons/screen/android/splash-land-ldpi.png b/mobile/icons/screen/android/splash-land-ldpi.png new file mode 100644 index 0000000..52c8227 Binary files /dev/null and b/mobile/icons/screen/android/splash-land-ldpi.png differ diff --git a/mobile/icons/screen/android/splash-land-mdpi.png b/mobile/icons/screen/android/splash-land-mdpi.png new file mode 100644 index 0000000..c72bc70 Binary files /dev/null and b/mobile/icons/screen/android/splash-land-mdpi.png differ diff --git a/mobile/icons/screen/android/splash-land-xhdpi.png b/mobile/icons/screen/android/splash-land-xhdpi.png new file mode 100644 index 0000000..227e703 Binary files /dev/null and b/mobile/icons/screen/android/splash-land-xhdpi.png differ diff --git a/mobile/icons/screen/android/splash-port-hdpi.png b/mobile/icons/screen/android/splash-port-hdpi.png new file mode 100644 index 0000000..1d197aa Binary files /dev/null and b/mobile/icons/screen/android/splash-port-hdpi.png differ diff --git a/mobile/icons/screen/android/splash-port-ldpi.png b/mobile/icons/screen/android/splash-port-ldpi.png new file mode 100644 index 0000000..af2c469 Binary files /dev/null and b/mobile/icons/screen/android/splash-port-ldpi.png differ diff --git a/mobile/icons/screen/android/splash-port-mdpi.png b/mobile/icons/screen/android/splash-port-mdpi.png new file mode 100644 index 0000000..15cd5c5 Binary files /dev/null and b/mobile/icons/screen/android/splash-port-mdpi.png differ diff --git a/mobile/icons/screen/android/splash-port-xhdpi.png b/mobile/icons/screen/android/splash-port-xhdpi.png new file mode 100644 index 0000000..5be827a Binary files /dev/null and b/mobile/icons/screen/android/splash-port-xhdpi.png differ diff --git a/mobile/icons/screen/ios/Default-568h@2x~iphone.png b/mobile/icons/screen/ios/Default-568h@2x~iphone.png new file mode 100644 index 0000000..8e75f7a Binary files /dev/null and b/mobile/icons/screen/ios/Default-568h@2x~iphone.png differ diff --git a/mobile/icons/screen/ios/Default-667h.png b/mobile/icons/screen/ios/Default-667h.png new file mode 100644 index 0000000..30e6a42 Binary files /dev/null and b/mobile/icons/screen/ios/Default-667h.png differ diff --git a/mobile/icons/screen/ios/Default-736h.png b/mobile/icons/screen/ios/Default-736h.png new file mode 100644 index 0000000..8e5405d Binary files /dev/null and b/mobile/icons/screen/ios/Default-736h.png differ diff --git a/mobile/icons/screen/ios/Default-Landscape-736h.png b/mobile/icons/screen/ios/Default-Landscape-736h.png new file mode 100644 index 0000000..27ec5f2 Binary files /dev/null and b/mobile/icons/screen/ios/Default-Landscape-736h.png differ diff --git a/mobile/icons/screen/ios/Default-Landscape@2x~ipad.png b/mobile/icons/screen/ios/Default-Landscape@2x~ipad.png new file mode 100644 index 0000000..b47030a Binary files /dev/null and b/mobile/icons/screen/ios/Default-Landscape@2x~ipad.png differ diff --git a/mobile/icons/screen/ios/Default-Landscape~ipad.png b/mobile/icons/screen/ios/Default-Landscape~ipad.png new file mode 100644 index 0000000..ebffbb4 Binary files /dev/null and b/mobile/icons/screen/ios/Default-Landscape~ipad.png differ diff --git a/mobile/icons/screen/ios/Default-Portrait@2x~ipad.png b/mobile/icons/screen/ios/Default-Portrait@2x~ipad.png new file mode 100644 index 0000000..4a6301a Binary files /dev/null and b/mobile/icons/screen/ios/Default-Portrait@2x~ipad.png differ diff --git a/mobile/icons/screen/ios/Default-Portrait~ipad.png b/mobile/icons/screen/ios/Default-Portrait~ipad.png new file mode 100644 index 0000000..e667955 Binary files /dev/null and b/mobile/icons/screen/ios/Default-Portrait~ipad.png differ diff --git a/mobile/icons/screen/ios/Default@2x~iphone.png b/mobile/icons/screen/ios/Default@2x~iphone.png new file mode 100644 index 0000000..2bc054f Binary files /dev/null and b/mobile/icons/screen/ios/Default@2x~iphone.png differ diff --git a/mobile/icons/screen/ios/Default~iphone.png b/mobile/icons/screen/ios/Default~iphone.png new file mode 100644 index 0000000..15cd5c5 Binary files /dev/null and b/mobile/icons/screen/ios/Default~iphone.png differ diff --git a/mobile/platforms/android/src/org/nxt/mobile/wallet/MainActivity.java b/mobile/platforms/android/src/org/nxt/mobile/wallet/MainActivity.java new file mode 100644 index 0000000..69c1683 --- /dev/null +++ b/mobile/platforms/android/src/org/nxt/mobile/wallet/MainActivity.java @@ -0,0 +1,41 @@ +/* + 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.nxt.mobile.wallet; + +import android.os.Bundle; +import android.webkit.WebView; +import android.webkit.WebSettings; + +import org.apache.cordova.*; + +public class MainActivity extends CordovaActivity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Set by in config.xml + loadUrl(launchUrl); + WebView webView = (WebView)appView.getEngine().getView(); + WebSettings settings = webView.getSettings(); + settings.setBuiltInZoomControls(true); + settings.setDisplayZoomControls(false); + settings.setSupportZoom(true); + } +} diff --git a/mobile/plugins/android.json b/mobile/plugins/android.json new file mode 100644 index 0000000..64e19bb --- /dev/null +++ b/mobile/plugins/android.json @@ -0,0 +1,48 @@ +{ + "prepare_queue": { + "installed": [], + "uninstalled": [] + }, + "config_munge": { + "files": {} + }, + "installed_plugins": { + "cordova-plugin-device": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova-plugin-console": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova-plugin-whitelist": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova-plugin-splashscreen": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova-plugin-statusbar": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "ionic-plugin-keyboard": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova-plugin-android-permissions": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova-plugin-compat": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova-plugin-file": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova-plugin-inappbrowser": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "cordova.plugins.diagnostic": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + }, + "phonegap-plugin-barcodescanner": { + "PACKAGE_NAME": "org.nxt.mobile.wallet" + } + }, + "dependent_plugins": {} +} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-android-permissions/LICENSE b/mobile/plugins/cordova-plugin-android-permissions/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/mobile/plugins/cordova-plugin-android-permissions/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed 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. + diff --git a/mobile/plugins/cordova-plugin-android-permissions/README.md b/mobile/plugins/cordova-plugin-android-permissions/README.md new file mode 100644 index 0000000..0f0f162 --- /dev/null +++ b/mobile/plugins/cordova-plugin-android-permissions/README.md @@ -0,0 +1,88 @@ +Android permission Cordova plugin +======== + +This plugin is designed for supporting Android new permissions checking mechanism. + +Since Android 6.0, the Android permissions checking mechanism has been changed. In the past, the permissions were granted by users when they decide to install the app. Now, the permissions should be granted by a user when he/she is using the app. + +For old Android plugins you (developers) are using may not support this new mechanism or already stop updating. So either to find a new plugin to solving this problem, nor trying to add the mechanism in the old plugin. If you don't want to do those, you can try this plugin. + +Installation +-------- + +```bash +cordova plugin add cordova-plugin-android-permissions@0.10.0 +``` + +※ Support Android SDK >= 14 + +Usage +-------- + +### API + +```javascript +var permissions = cordova.plugins.permissions; +permissions.hasPermission(permission, successCallback, errorCallback); +permissions.requestPermission(permission, successCallback, errorCallback); +permissions.requestPermissions(permissions, successCallback, errorCallback); +``` + +#### Deprecated API - still work now, will not support in the future. +```javascript +permissions.hasPermission(successCallback, errorCallback, permission); +permissions.requestPermission(successCallback, errorCallback, permission); +``` + +### Permission Name + +Following the Android design. See [Manifest.permission](http://developer.android.com/intl/zh-tw/reference/android/Manifest.permission.html). +```javascript +// Example +permissions.ACCESS_COARSE_LOCATION +permissions.CAMERA +permissions.GET_ACCOUNTS +permissions.READ_CONTACTS +permissions.READ_CALENDAR +... +``` + +Example +-------- + +```javascript +var permissions = cordova.plugins.permissions; +permissions.hasPermission(permissions.CAMERA, checkPermissionCallback, null); + +function checkPermissionCallback(status) { + if(!status.hasPermission) { + var errorCallback = function() { + console.warn('Camera permission is not turned on'); + } + + permissions.requestPermission( + permissions.CAMERA, + function(status) { + if(!status.hasPermission) errorCallback(); + }, + errorCallback); + } +} +``` + +License +-------- + + Copyright (C) 2016 Jason Yang + + Licensed 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. diff --git a/mobile/plugins/cordova-plugin-android-permissions/package.json b/mobile/plugins/cordova-plugin-android-permissions/package.json new file mode 100644 index 0000000..003fe57 --- /dev/null +++ b/mobile/plugins/cordova-plugin-android-permissions/package.json @@ -0,0 +1,31 @@ +{ + "name": "cordova-plugin-android-permissions", + "version": "0.10.0", + "description": "Android 6.0 permissions check.", + "cordova": { + "id": "cordova-plugin-android-permissions", + "platforms": [ + "android" + ] + }, + "repository": { + "type": "git", + "url": "git+https://github.com/NeoLSN/cordova-plugin-android-permission.git" + }, + "keywords": [ + "ecosystem:cordova", + "cordova-android" + ], + "engines": [ + { + "name": "cordova", + "version": ">=5.0.0" + } + ], + "author": "Jason Yang", + "license": "BSD", + "bugs": { + "url": "https://github.com/NeoLSN/cordova-plugin-android-permission/issues" + }, + "homepage": "https://github.com/NeoLSN/cordova-plugin-android-permission#readme" +} diff --git a/mobile/plugins/cordova-plugin-android-permissions/plugin.xml b/mobile/plugins/cordova-plugin-android-permissions/plugin.xml new file mode 100644 index 0000000..1c45413 --- /dev/null +++ b/mobile/plugins/cordova-plugin-android-permissions/plugin.xml @@ -0,0 +1,32 @@ + + + + Permissions + + Android permissions support library. + + Jason Yang + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/plugins/cordova-plugin-android-permissions/src/android/com/android/plugins/Permissions.java b/mobile/plugins/cordova-plugin-android-permissions/src/android/com/android/plugins/Permissions.java new file mode 100644 index 0000000..64d3213 --- /dev/null +++ b/mobile/plugins/cordova-plugin-android-permissions/src/android/com/android/plugins/Permissions.java @@ -0,0 +1,156 @@ +package com.android.plugins; + +import android.os.Build; + +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Created by JasonYang on 2016/3/11. + */ +public class Permissions extends CordovaPlugin { + + private static final String ACTION_HAS_PERMISSION = "hasPermission"; + private static final String ACTION_REQUEST_PERMISSION = "requestPermission"; + private static final String ACTION_REQUEST_PERMISSIONS = "requestPermissions"; + + private static final int REQUEST_CODE_ENABLE_PERMISSION = 55433; + + private static final String KEY_ERROR = "error"; + private static final String KEY_MESSAGE = "message"; + + private CallbackContext permissionsCallback; + + @Override + public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { + if (ACTION_HAS_PERMISSION.equals(action)) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + hasPermissionAction(callbackContext, args); + } + }); + return true; + } else if (ACTION_REQUEST_PERMISSION.equals(action) || ACTION_REQUEST_PERMISSIONS.equals(action)) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + requestPermissionAction(callbackContext, args); + } catch (Exception e) { + e.printStackTrace(); + JSONObject returnObj = new JSONObject(); + addProperty(returnObj, KEY_ERROR, ACTION_REQUEST_PERMISSION); + addProperty(returnObj, KEY_MESSAGE, "Request permission has been denied."); + callbackContext.error(returnObj); + permissionsCallback = null; + } + } + }); + return true; + } + return false; + } + + @Override + public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException { + if (permissionsCallback == null) { + return; + } + + JSONObject returnObj = new JSONObject(); + if (permissions != null && permissions.length > 0) { + //Call hasPermission again to verify + boolean hasAllPermissions = hasAllPermissions(permissions); + addProperty(returnObj, ACTION_HAS_PERMISSION, hasAllPermissions); + permissionsCallback.success(returnObj); + } else { + addProperty(returnObj, KEY_ERROR, ACTION_REQUEST_PERMISSION); + addProperty(returnObj, KEY_MESSAGE, "Unknown error."); + permissionsCallback.error(returnObj); + } + permissionsCallback = null; + } + + private void hasPermissionAction(CallbackContext callbackContext, JSONArray permission) { + if (permission == null || permission.length() == 0 || permission.length() > 1) { + JSONObject returnObj = new JSONObject(); + addProperty(returnObj, KEY_ERROR, ACTION_HAS_PERMISSION); + addProperty(returnObj, KEY_MESSAGE, "One time one permission only."); + callbackContext.error(returnObj); + } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + JSONObject returnObj = new JSONObject(); + addProperty(returnObj, ACTION_HAS_PERMISSION, true); + callbackContext.success(returnObj); + } else { + try { + JSONObject returnObj = new JSONObject(); + addProperty(returnObj, ACTION_HAS_PERMISSION, cordova.hasPermission(permission.getString(0))); + callbackContext.success(returnObj); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + + private void requestPermissionAction(CallbackContext callbackContext, JSONArray permissions) throws Exception { + if (permissions == null || permissions.length() == 0) { + JSONObject returnObj = new JSONObject(); + addProperty(returnObj, KEY_ERROR, ACTION_REQUEST_PERMISSION); + addProperty(returnObj, KEY_MESSAGE, "At least one permission."); + callbackContext.error(returnObj); + } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + JSONObject returnObj = new JSONObject(); + addProperty(returnObj, ACTION_HAS_PERMISSION, true); + callbackContext.success(returnObj); + } else if (hasAllPermissions(permissions)) { + JSONObject returnObj = new JSONObject(); + addProperty(returnObj, ACTION_HAS_PERMISSION, true); + callbackContext.success(returnObj); + } else { + permissionsCallback = callbackContext; + String[] permissionArray = getPermissions(permissions); + cordova.requestPermissions(this, REQUEST_CODE_ENABLE_PERMISSION, permissionArray); + } + } + + private String[] getPermissions(JSONArray permissions) { + String[] stringArray = new String[permissions.length()]; + for (int i = 0; i < permissions.length(); i++) { + try { + stringArray[i] = permissions.getString(i); + } catch (JSONException ignored) { + //Believe exception only occurs when adding duplicate keys, so just ignore it + } + } + return stringArray; + } + + private boolean hasAllPermissions(JSONArray permissions) throws JSONException { + return hasAllPermissions(getPermissions(permissions)); + } + + private boolean hasAllPermissions(String[] permissions) throws JSONException { + + for (String permission : permissions) { + if(!cordova.hasPermission(permission)) { + return false; + } + } + + return true; + } + + private void addProperty(JSONObject obj, String key, Object value) { + try { + if (value == null) { + obj.put(key, JSONObject.NULL); + } else { + obj.put(key, value); + } + } catch (JSONException ignored) { + //Believe exception only occurs when adding duplicate keys, so just ignore it + } + } +} diff --git a/mobile/plugins/cordova-plugin-android-permissions/www/permissions.js b/mobile/plugins/cordova-plugin-android-permissions/www/permissions.js new file mode 100644 index 0000000..b59b838 --- /dev/null +++ b/mobile/plugins/cordova-plugin-android-permissions/www/permissions.js @@ -0,0 +1,187 @@ +var permissionsName = 'Permissions'; + +function Permissions() { + + this.ACCESS_CHECKIN_PROPERTIES = 'android.permission.ACCESS_CHECKIN_PROPERTIES'; + this.ACCESS_COARSE_LOCATION = 'android.permission.ACCESS_COARSE_LOCATION'; + this.ACCESS_FINE_LOCATION = 'android.permission.ACCESS_FINE_LOCATION'; + this.ACCESS_LOCATION_EXTRA_COMMANDS = 'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS'; + this.ACCESS_MOCK_LOCATION = 'android.permission.ACCESS_MOCK_LOCATION'; + this.ACCESS_NETWORK_STATE = 'android.permission.ACCESS_NETWORK_STATE'; + this.ACCESS_SURFACE_FLINGER = 'android.permission.ACCESS_SURFACE_FLINGER'; + this.ACCESS_WIFI_STATE = 'android.permission.ACCESS_WIFI_STATE'; + this.ACCOUNT_MANAGER = 'android.permission.ACCOUNT_MANAGER'; + this.ADD_VOICEMAIL = 'com.android.voicemail.permission.ADD_VOICEMAIL'; + this.AUTHENTICATE_ACCOUNTS = 'android.permission.AUTHENTICATE_ACCOUNTS'; + this.BATTERY_STATS = 'android.permission.BATTERY_STATS'; + this.BIND_ACCESSIBILITY_SERVICE = 'android.permission.BIND_ACCESSIBILITY_SERVICE'; + this.BIND_APPWIDGET = 'android.permission.BIND_APPWIDGET'; + this.BIND_CARRIER_MESSAGING_SERVICE = 'android.permission.BIND_CARRIER_MESSAGING_SERVICE'; + this.BIND_DEVICE_ADMIN = 'android.permission.BIND_DEVICE_ADMIN'; + this.BIND_DREAM_SERVICE = 'android.permission.BIND_DREAM_SERVICE'; + this.BIND_INPUT_METHOD = 'android.permission.BIND_INPUT_METHOD'; + this.BIND_NFC_SERVICE = 'android.permission.BIND_NFC_SERVICE'; + this.BIND_NOTIFICATION_LISTENER_SERVICE = 'android.permission.BIND_NOTIFICATION_LISTENER_SERVICE'; + this.BIND_PRINT_SERVICE = 'android.permission.BIND_PRINT_SERVICE'; + this.BIND_REMOTEVIEWS = 'android.permission.BIND_REMOTEVIEWS'; + this.BIND_TEXT_SERVICE = 'android.permission.BIND_TEXT_SERVICE'; + this.BIND_TV_INPUT = 'android.permission.BIND_TV_INPUT'; + this.BIND_VOICE_INTERACTION = 'android.permission.BIND_VOICE_INTERACTION'; + this.BIND_VPN_SERVICE = 'android.permission.BIND_VPN_SERVICE'; + this.BIND_WALLPAPER = 'android.permission.BIND_WALLPAPER'; + this.BLUETOOTH = 'android.permission.BLUETOOTH'; + this.BLUETOOTH_ADMIN = 'android.permission.BLUETOOTH_ADMIN'; + this.BLUETOOTH_PRIVILEGED = 'android.permission.BLUETOOTH_PRIVILEGED'; + this.BODY_SENSORS = 'android.permission.BODY_SENSORS'; + this.BRICK = 'android.permission.BRICK'; + this.BROADCAST_PACKAGE_REMOVED = 'android.permission.BROADCAST_PACKAGE_REMOVED'; + this.BROADCAST_SMS = 'android.permission.BROADCAST_SMS'; + this.BROADCAST_STICKY = 'android.permission.BROADCAST_STICKY'; + this.BROADCAST_WAP_PUSH = 'android.permission.BROADCAST_WAP_PUSH'; + this.CALL_PHONE = 'android.permission.CALL_PHONE'; + this.CALL_PRIVILEGED = 'android.permission.CALL_PRIVILEGED'; + this.CAMERA = 'android.permission.CAMERA'; + this.CAPTURE_AUDIO_OUTPUT = 'android.permission.CAPTURE_AUDIO_OUTPUT'; + this.CAPTURE_SECURE_VIDEO_OUTPUT = 'android.permission.CAPTURE_SECURE_VIDEO_OUTPUT'; + this.CAPTURE_VIDEO_OUTPUT = 'android.permission.CAPTURE_VIDEO_OUTPUT'; + this.CHANGE_COMPONENT_ENABLED_STATE = 'android.permission.CHANGE_COMPONENT_ENABLED_STATE'; + this.CHANGE_CONFIGURATION = 'android.permission.CHANGE_CONFIGURATION'; + this.CHANGE_NETWORK_STATE = 'android.permission.CHANGE_NETWORK_STATE'; + this.CHANGE_WIFI_MULTICAST_STATE = 'android.permission.CHANGE_WIFI_MULTICAST_STATE'; + this.CHANGE_WIFI_STATE = 'android.permission.CHANGE_WIFI_STATE'; + this.CLEAR_APP_CACHE = 'android.permission.CLEAR_APP_CACHE'; + this.CLEAR_APP_USER_DATA = 'android.permission.CLEAR_APP_USER_DATA'; + this.CONTROL_LOCATION_UPDATES = 'android.permission.CONTROL_LOCATION_UPDATES'; + this.DELETE_CACHE_FILES = 'android.permission.DELETE_CACHE_FILES'; + this.DELETE_PACKAGES = 'android.permission.DELETE_PACKAGES'; + this.DEVICE_POWER = 'android.permission.DEVICE_POWER'; + this.DIAGNOSTIC = 'android.permission.DIAGNOSTIC'; + this.DISABLE_KEYGUARD = 'android.permission.DISABLE_KEYGUARD'; + this.DUMP = 'android.permission.DUMP'; + this.EXPAND_STATUS_BAR = 'android.permission.EXPAND_STATUS_BAR'; + this.FACTORY_TEST = 'android.permission.FACTORY_TEST'; + this.FLASHLIGHT = 'android.permission.FLASHLIGHT'; + this.FORCE_BACK = 'android.permission.FORCE_BACK'; + this.GET_ACCOUNTS = 'android.permission.GET_ACCOUNTS'; + this.GET_PACKAGE_SIZE = 'android.permission.GET_PACKAGE_SIZE'; + this.GET_TASKS = 'android.permission.GET_TASKS'; + this.GET_TOP_ACTIVITY_INFO = 'android.permission.GET_TOP_ACTIVITY_INFO'; + this.GLOBAL_SEARCH = 'android.permission.GLOBAL_SEARCH'; + this.HARDWARE_TEST = 'android.permission.HARDWARE_TEST'; + this.INJECT_EVENTS = 'android.permission.INJECT_EVENTS'; + this.INSTALL_LOCATION_PROVIDER = 'android.permission.INSTALL_LOCATION_PROVIDER'; + this.INSTALL_PACKAGES = 'android.permission.INSTALL_PACKAGES'; + this.INSTALL_SHORTCUT = 'com.android.launcher.permission.INSTALL_SHORTCUT'; + this.INTERNAL_SYSTEM_WINDOW = 'android.permission.INTERNAL_SYSTEM_WINDOW'; + this.INTERNET = 'android.permission.INTERNET'; + this.KILL_BACKGROUND_PROCESSES = 'android.permission.KILL_BACKGROUND_PROCESSES'; + this.LOCATION_HARDWARE = 'android.permission.LOCATION_HARDWARE'; + this.MANAGE_ACCOUNTS = 'android.permission.MANAGE_ACCOUNTS'; + this.MANAGE_APP_TOKENS = 'android.permission.MANAGE_APP_TOKENS'; + this.MANAGE_DOCUMENTS = 'android.permission.MANAGE_DOCUMENTS'; + this.MASTER_CLEAR = 'android.permission.MASTER_CLEAR'; + this.MEDIA_CONTENT_CONTROL = 'android.permission.MEDIA_CONTENT_CONTROL'; + this.MODIFY_AUDIO_SETTINGS = 'android.permission.MODIFY_AUDIO_SETTINGS'; + this.MODIFY_PHONE_STATE = 'android.permission.MODIFY_PHONE_STATE'; + this.MOUNT_FORMAT_FILESYSTEMS = 'android.permission.MOUNT_FORMAT_FILESYSTEMS'; + this.MOUNT_UNMOUNT_FILESYSTEMS = 'android.permission.MOUNT_UNMOUNT_FILESYSTEMS'; + this.NFC = 'android.permission.NFC'; + this.PERSISTENT_ACTIVITY = 'android.permission.PERSISTENT_ACTIVITY'; + this.PROCESS_OUTGOING_CALLS = 'android.permission.PROCESS_OUTGOING_CALLS'; + this.READ_CALENDAR = 'android.permission.READ_CALENDAR'; + this.READ_CALL_LOG = 'android.permission.READ_CALL_LOG'; + this.READ_CONTACTS = 'android.permission.READ_CONTACTS'; + this.READ_EXTERNAL_STORAGE = 'android.permission.READ_EXTERNAL_STORAGE'; + this.READ_FRAME_BUFFER = 'android.permission.READ_FRAME_BUFFER'; + this.READ_HISTORY_BOOKMARKS = 'com.android.browser.permission.READ_HISTORY_BOOKMARKS'; + this.READ_INPUT_STATE = 'android.permission.READ_INPUT_STATE'; + this.READ_LOGS = 'android.permission.READ_LOGS'; + this.READ_PHONE_STATE = 'android.permission.READ_PHONE_STATE'; + this.READ_PROFILE = 'android.permission.READ_PROFILE'; + this.READ_SMS = 'android.permission.READ_SMS'; + this.READ_SOCIAL_STREAM = 'android.permission.READ_SOCIAL_STREAM'; + this.READ_SYNC_SETTINGS = 'android.permission.READ_SYNC_SETTINGS'; + this.READ_SYNC_STATS = 'android.permission.READ_SYNC_STATS'; + this.READ_USER_DICTIONARY = 'android.permission.READ_USER_DICTIONARY'; + this.READ_VOICEMAIL = 'com.android.voicemail.permission.READ_VOICEMAIL'; + this.REBOOT = 'android.permission.REBOOT'; + this.RECEIVE_BOOT_COMPLETED = 'android.permission.RECEIVE_BOOT_COMPLETED'; + this.RECEIVE_MMS = 'android.permission.RECEIVE_MMS'; + this.RECEIVE_SMS = 'android.permission.RECEIVE_SMS'; + this.RECEIVE_WAP_PUSH = 'android.permission.RECEIVE_WAP_PUSH'; + this.RECORD_AUDIO = 'android.permission.RECORD_AUDIO'; + this.REORDER_TASKS = 'android.permission.REORDER_TASKS'; + this.RESTART_PACKAGES = 'android.permission.RESTART_PACKAGES'; + this.SEND_RESPOND_VIA_MESSAGE = 'android.permission.SEND_RESPOND_VIA_MESSAGE'; + this.SEND_SMS = 'android.permission.SEND_SMS'; + this.SET_ACTIVITY_WATCHER = 'android.permission.SET_ACTIVITY_WATCHER'; + this.SET_ALARM = 'com.android.alarm.permission.SET_ALARM'; + this.SET_ALWAYS_FINISH = 'android.permission.SET_ALWAYS_FINISH'; + this.SET_ANIMATION_SCALE = 'android.permission.SET_ANIMATION_SCALE'; + this.SET_DEBUG_APP = 'android.permission.SET_DEBUG_APP'; + this.SET_ORIENTATION = 'android.permission.SET_ORIENTATION'; + this.SET_POINTER_SPEED = 'android.permission.SET_POINTER_SPEED'; + this.SET_PREFERRED_APPLICATIONS = 'android.permission.SET_PREFERRED_APPLICATIONS'; + this.SET_PROCESS_LIMIT = 'android.permission.SET_PROCESS_LIMIT'; + this.SET_TIME = 'android.permission.SET_TIME'; + this.SET_TIME_ZONE = 'android.permission.SET_TIME_ZONE'; + this.SET_WALLPAPER = 'android.permission.SET_WALLPAPER'; + this.SET_WALLPAPER_HINTS = 'android.permission.SET_WALLPAPER_HINTS'; + this.SIGNAL_PERSISTENT_PROCESSES = 'android.permission.SIGNAL_PERSISTENT_PROCESSES'; + this.STATUS_BAR = 'android.permission.STATUS_BAR'; + this.SUBSCRIBED_FEEDS_READ = 'android.permission.SUBSCRIBED_FEEDS_READ'; + this.SUBSCRIBED_FEEDS_WRITE = 'android.permission.SUBSCRIBED_FEEDS_WRITE'; + this.SYSTEM_ALERT_WINDOW = 'android.permission.SYSTEM_ALERT_WINDOW'; + this.TRANSMIT_IR = 'android.permission.TRANSMIT_IR'; + this.UNINSTALL_SHORTCUT = 'com.android.launcher.permission.UNINSTALL_SHORTCUT'; + this.UPDATE_DEVICE_STATS = 'android.permission.UPDATE_DEVICE_STATS'; + this.USE_CREDENTIALS = 'android.permission.USE_CREDENTIALS'; + this.USE_SIP = 'android.permission.USE_SIP'; + this.VIBRATE = 'android.permission.VIBRATE'; + this.WAKE_LOCK = 'android.permission.WAKE_LOCK'; + this.WRITE_APN_SETTINGS = 'android.permission.WRITE_APN_SETTINGS'; + this.WRITE_CALENDAR = 'android.permission.WRITE_CALENDAR'; + this.WRITE_CALL_LOG = 'android.permission.WRITE_CALL_LOG'; + this.WRITE_CONTACTS = 'android.permission.WRITE_CONTACTS'; + this.WRITE_EXTERNAL_STORAGE = 'android.permission.WRITE_EXTERNAL_STORAGE'; + this.WRITE_GSERVICES = 'android.permission.WRITE_GSERVICES'; + this.WRITE_HISTORY_BOOKMARKS = 'com.android.browser.permission.WRITE_HISTORY_BOOKMARKS'; + this.WRITE_PROFILE = 'android.permission.WRITE_PROFILE'; + this.WRITE_SECURE_SETTINGS = 'android.permission.WRITE_SECURE_SETTINGS'; + this.WRITE_SETTINGS = 'android.permission.WRITE_SETTINGS'; + this.WRITE_SMS = 'android.permission.WRITE_SMS'; + this.WRITE_SOCIAL_STREAM = 'android.permission.WRITE_SOCIAL_STREAM'; + this.WRITE_SYNC_SETTINGS = 'android.permission.WRITE_SYNC_SETTINGS'; + this.WRITE_USER_DICTIONARY = 'android.permission.WRITE_USER_DICTIONARY'; + this.WRITE_VOICEMAIL = 'com.android.voicemail.permission.WRITE_VOICEMAIL'; +} + +function deprecated(name) { + console.warn("Calling cordova.plugins.permissions." + name + " with the successCallback as first argument is deprecated"); + console.warn("The new signature is '" + name + "(permission, successCallback, errorCallback)'"); +} + +Permissions.prototype = { + hasPermission: function(permission, successCallback, errorCallback) { + if (typeof permission === "function") { + deprecated("hasPermission"); + successCallback = arguments[0]; + errorCallback = arguments[1]; + permission = arguments[2]; + } + cordova.exec(successCallback, errorCallback, permissionsName, 'hasPermission', [permission]); + }, + requestPermission: function(permission, successCallback, errorCallback) { + if (typeof permission === "function") { + deprecated("requestPermission"); + successCallback = arguments[0]; + errorCallback = arguments[1]; + permission = arguments[2]; + } + cordova.exec(successCallback, errorCallback, permissionsName, 'requestPermission', [permission]); + }, + requestPermissions: function(permissions, successCallback, errorCallback) { + cordova.exec(successCallback, errorCallback, permissionsName, 'requestPermissions', permissions); + } +}; +module.exports = new Permissions(); diff --git a/mobile/plugins/cordova-plugin-compat/README.md b/mobile/plugins/cordova-plugin-compat/README.md new file mode 100644 index 0000000..095c384 --- /dev/null +++ b/mobile/plugins/cordova-plugin-compat/README.md @@ -0,0 +1,31 @@ + + +cordova-plugin-compat +------------------------ + +This repo is for remaining backwards compatible with previous versions of Cordova. + +## USAGE + +Your plugin can depend on this plugin and use it to handle the new run time permissions Android 6.0.0 (cordova-android 5.0.0) introduced. + +View [this commit](https://github.com/apache/cordova-plugin-camera/commit/a9c18710f23e86f5b7f8918dfab7c87a85064870) to see how to depend on `cordova-plugin-compat`. View [this file](https://github.com/apache/cordova-plugin-camera/blob/master/src/android/CameraLauncher.java) to see how `PermissionHelper` is being used to request and store permissions. Read more about Android permissions at http://cordova.apache.org/docs/en/latest/guide/platforms/android/plugin.html#android-permissions. diff --git a/mobile/plugins/cordova-plugin-compat/RELEASENOTES.md b/mobile/plugins/cordova-plugin-compat/RELEASENOTES.md new file mode 100644 index 0000000..b7aa129 --- /dev/null +++ b/mobile/plugins/cordova-plugin-compat/RELEASENOTES.md @@ -0,0 +1,29 @@ + +# Release Notes + +### 1.1.0 (Nov 02, 2016) +* [CB-11625](https://issues.apache.org/jira/browse/CB-11625) Adding the `BuildConfig` fetching code as a backup to using a new preference +* Add github pull request template + +### 1.0.0 (Apr 15, 2016) +* Initial release +* Moved `PermissionHelper.java` into `src` diff --git a/mobile/plugins/cordova-plugin-compat/package.json b/mobile/plugins/cordova-plugin-compat/package.json new file mode 100644 index 0000000..f31174d --- /dev/null +++ b/mobile/plugins/cordova-plugin-compat/package.json @@ -0,0 +1,32 @@ +{ + "name": "cordova-plugin-compat", + "description": "This repo is for remaining backwards compatible with previous versions of Cordova.", + "version": "1.1.0", + "homepage": "http://github.com/apache/cordova-plugin-compat#readme", + "repository": { + "type": "git", + "url": "git://github.com/apache/cordova-plugin-compat.git" + }, + "bugs": { + "url": "https://github.com/apache/cordova-plugin-compat/issues" + }, + "cordova": { + "id": "cordova-plugin-compat", + "platforms": [ + "android" + ] + }, + "keywords": [ + "ecosystem:cordova", + "ecosystem:phonegap", + "cordova-android" + ], + "engines": [ + { + "name": "cordova", + "version": ">=5.0.0" + } + ], + "author": "Apache Software Foundation", + "license": "Apache-2.0" +} diff --git a/mobile/plugins/cordova-plugin-compat/plugin.xml b/mobile/plugins/cordova-plugin-compat/plugin.xml new file mode 100644 index 0000000..40b45cc --- /dev/null +++ b/mobile/plugins/cordova-plugin-compat/plugin.xml @@ -0,0 +1,37 @@ + + + + + + Compat + Cordova Compatibility Plugin + Apache 2.0 + cordova,compat + https://git-wip-us.apache.org/repos/asf/cordova-plugin-compat.git + + + + + + + + diff --git a/mobile/plugins/cordova-plugin-compat/src/android/BuildHelper.java b/mobile/plugins/cordova-plugin-compat/src/android/BuildHelper.java new file mode 100644 index 0000000..d9b18aa --- /dev/null +++ b/mobile/plugins/cordova-plugin-compat/src/android/BuildHelper.java @@ -0,0 +1,70 @@ +/* + 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.cordova; + +/* + * This is a utility class that allows us to get the BuildConfig variable, which is required + * for the use of different providers. This is not guaranteed to work, and it's better for this + * to be set in the build step in config.xml + * + */ + +import android.app.Activity; +import android.content.Context; + +import java.lang.reflect.Field; + + +public class BuildHelper { + + + private static String TAG="BuildHelper"; + + /* + * This needs to be implemented if you wish to use the Camera Plugin or other plugins + * that read the Build Configuration. + * + * Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to + * StackOverflow. This is annoying as hell! However, this method does not work with + * ProGuard, and you should use the config.xml to define the application_id + * + */ + + public static Object getBuildConfigValue(Context ctx, String key) + { + try + { + Class clazz = Class.forName(ctx.getPackageName() + ".BuildConfig"); + Field field = clazz.getField(key); + return field.get(null); + } catch (ClassNotFoundException e) { + LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?"); + e.printStackTrace(); + } catch (NoSuchFieldException e) { + LOG.d(TAG, key + " is not a valid field. Check your build.gradle"); + } catch (IllegalAccessException e) { + LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace."); + e.printStackTrace(); + } + + return null; + } + +} diff --git a/mobile/plugins/cordova-plugin-compat/src/android/PermissionHelper.java b/mobile/plugins/cordova-plugin-compat/src/android/PermissionHelper.java new file mode 100644 index 0000000..bbd7911 --- /dev/null +++ b/mobile/plugins/cordova-plugin-compat/src/android/PermissionHelper.java @@ -0,0 +1,138 @@ +/* + 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.cordova; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; + +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.LOG; + +import android.content.pm.PackageManager; + +/** + * This class provides reflective methods for permission requesting and checking so that plugins + * written for cordova-android 5.0.0+ can still compile with earlier cordova-android versions. + */ +public class PermissionHelper { + private static final String LOG_TAG = "CordovaPermissionHelper"; + + /** + * Requests a "dangerous" permission for the application at runtime. This is a helper method + * alternative to cordovaInterface.requestPermission() that does not require the project to be + * built with cordova-android 5.0.0+ + * + * @param plugin The plugin the permission is being requested for + * @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult() + * along with the result of the permission request + * @param permission The permission to be requested + */ + public static void requestPermission(CordovaPlugin plugin, int requestCode, String permission) { + PermissionHelper.requestPermissions(plugin, requestCode, new String[] {permission}); + } + + /** + * Requests "dangerous" permissions for the application at runtime. This is a helper method + * alternative to cordovaInterface.requestPermissions() that does not require the project to be + * built with cordova-android 5.0.0+ + * + * @param plugin The plugin the permissions are being requested for + * @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult() + * along with the result of the permissions request + * @param permissions The permissions to be requested + */ + public static void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) { + try { + Method requestPermission = CordovaInterface.class.getDeclaredMethod( + "requestPermissions", CordovaPlugin.class, int.class, String[].class); + + // If there is no exception, then this is cordova-android 5.0.0+ + requestPermission.invoke(plugin.cordova, plugin, requestCode, permissions); + } catch (NoSuchMethodException noSuchMethodException) { + // cordova-android version is less than 5.0.0, so permission is implicitly granted + LOG.d(LOG_TAG, "No need to request permissions " + Arrays.toString(permissions)); + + // Notify the plugin that all were granted by using more reflection + deliverPermissionResult(plugin, requestCode, permissions); + } catch (IllegalAccessException illegalAccessException) { + // Should never be caught; this is a public method + LOG.e(LOG_TAG, "IllegalAccessException when requesting permissions " + Arrays.toString(permissions), illegalAccessException); + } catch(InvocationTargetException invocationTargetException) { + // This method does not throw any exceptions, so this should never be caught + LOG.e(LOG_TAG, "invocationTargetException when requesting permissions " + Arrays.toString(permissions), invocationTargetException); + } + } + + /** + * Checks at runtime to see if the application has been granted a permission. This is a helper + * method alternative to cordovaInterface.hasPermission() that does not require the project to + * be built with cordova-android 5.0.0+ + * + * @param plugin The plugin the permission is being checked against + * @param permission The permission to be checked + * + * @return True if the permission has already been granted and false otherwise + */ + public static boolean hasPermission(CordovaPlugin plugin, String permission) { + try { + Method hasPermission = CordovaInterface.class.getDeclaredMethod("hasPermission", String.class); + + // If there is no exception, then this is cordova-android 5.0.0+ + return (Boolean) hasPermission.invoke(plugin.cordova, permission); + } catch (NoSuchMethodException noSuchMethodException) { + // cordova-android version is less than 5.0.0, so permission is implicitly granted + LOG.d(LOG_TAG, "No need to check for permission " + permission); + return true; + } catch (IllegalAccessException illegalAccessException) { + // Should never be caught; this is a public method + LOG.e(LOG_TAG, "IllegalAccessException when checking permission " + permission, illegalAccessException); + } catch(InvocationTargetException invocationTargetException) { + // This method does not throw any exceptions, so this should never be caught + LOG.e(LOG_TAG, "invocationTargetException when checking permission " + permission, invocationTargetException); + } + return false; + } + + private static void deliverPermissionResult(CordovaPlugin plugin, int requestCode, String[] permissions) { + // Generate the request results + int[] requestResults = new int[permissions.length]; + Arrays.fill(requestResults, PackageManager.PERMISSION_GRANTED); + + try { + Method onRequestPermissionResult = CordovaPlugin.class.getDeclaredMethod( + "onRequestPermissionResult", int.class, String[].class, int[].class); + + onRequestPermissionResult.invoke(plugin, requestCode, permissions, requestResults); + } catch (NoSuchMethodException noSuchMethodException) { + // Should never be caught since the plugin must be written for cordova-android 5.0.0+ if it + // made it to this point + LOG.e(LOG_TAG, "NoSuchMethodException when delivering permissions results", noSuchMethodException); + } catch (IllegalAccessException illegalAccessException) { + // Should never be caught; this is a public method + LOG.e(LOG_TAG, "IllegalAccessException when delivering permissions results", illegalAccessException); + } catch(InvocationTargetException invocationTargetException) { + // This method may throw a JSONException. We are just duplicating cordova-android's + // exception handling behavior here; all it does is log the exception in CordovaActivity, + // print the stacktrace, and ignore it + LOG.e(LOG_TAG, "InvocationTargetException when delivering permissions results", invocationTargetException); + } + } +} diff --git a/mobile/plugins/cordova-plugin-console/CONTRIBUTING.md b/mobile/plugins/cordova-plugin-console/CONTRIBUTING.md new file mode 100644 index 0000000..4c8e6a5 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/CONTRIBUTING.md @@ -0,0 +1,37 @@ + + +# Contributing to Apache Cordova + +Anyone can contribute to Cordova. And we need your contributions. + +There are multiple ways to contribute: report bugs, improve the docs, and +contribute code. + +For instructions on this, start with the +[contribution overview](http://cordova.apache.org/contribute/). + +The details are explained there, but the important items are: + - Sign and submit an Apache ICLA (Contributor License Agreement). + - Have a Jira issue open that corresponds to your contribution. + - Run the tests so your patch doesn't break existing functionality. + +We look forward to your contributions! diff --git a/mobile/plugins/cordova-plugin-console/LICENSE b/mobile/plugins/cordova-plugin-console/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/NOTICE b/mobile/plugins/cordova-plugin-console/NOTICE new file mode 100644 index 0000000..8ec56a5 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/NOTICE @@ -0,0 +1,5 @@ +Apache Cordova +Copyright 2012 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). diff --git a/mobile/plugins/cordova-plugin-console/README.md b/mobile/plugins/cordova-plugin-console/README.md new file mode 100644 index 0000000..ebd0939 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/README.md @@ -0,0 +1,109 @@ +--- +title: Console +description: Get JavaScript logs in your native logs. +--- + + +|Android|iOS| Windows 8.1 Store | Windows 8.1 Phone | Windows 10 Store | Travis CI | +|:-:|:-:|:-:|:-:|:-:|:-:| +|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-console)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-console/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-console)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-console/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-console)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-console/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-console)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-console/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-console)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-console/)|[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-console) + +# cordova-plugin-console + +This plugin is meant to ensure that console.log() is as useful as it can be. +It adds additional function for iOS, Ubuntu, Windows Phone 8, and Windows. If +you are happy with how console.log() works for you, then you probably +don't need this plugin. + +This plugin defines a global `console` object. + +Although the object is in the global scope, features provided by this plugin +are not available until after the `deviceready` event. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + +:warning: Report issues on the [Apache Cordova issue tracker](https://issues.apache.org/jira/issues/?jql=project%20%3D%20CB%20AND%20status%20in%20%28Open%2C%20%22In%20Progress%22%2C%20Reopened%29%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20%22Plugin%20Console%22%20ORDER%20BY%20priority%20DESC%2C%20summary%20ASC%2C%20updatedDate%20DESC) + + +## Installation + + cordova plugin add cordova-plugin-console + +### Android Quirks + +On some platforms other than Android, console.log() will act on multiple +arguments, such as console.log("1", "2", "3"). However, Android will act only +on the first argument. Subsequent arguments to console.log() will be ignored. +This plugin is not the cause of that, it is a limitation of Android itself. + +## Supported Methods + +The plugin support following methods of the `console` object: + +- `console.log` +- `console.error` +- `console.exception` +- `console.warn` +- `console.info` +- `console.debug` +- `console.assert` +- `console.dir` +- `console.dirxml` +- `console.time` +- `console.timeEnd` +- `console.table` + +## Partially supported Methods + +Methods of the `console` object which implemented, but behave different from browser implementation: + +- `console.group` +- `console.groupCollapsed` + +The grouping methods are just log name of the group and don't actually indicate grouping for later +calls to `console` object methods. + +## Not supported Methods + +Methods of the `console` object which are implemented, but do nothing: + +- `console.clear` +- `console.trace` +- `console.groupEnd` +- `console.timeStamp` +- `console.profile` +- `console.profileEnd` +- `console.count` + +## Supported formatting + +The following formatting options available: + +Format chars: + +* `%j` - format arg as JSON +* `%o` - format arg as JSON +* `%c` - format arg as `''`. No color formatting could be done. +* `%%` - replace with `'%'` + +Any other char following `%` will format its arg via `toString()`. diff --git a/mobile/plugins/cordova-plugin-console/RELEASENOTES.md b/mobile/plugins/cordova-plugin-console/RELEASENOTES.md new file mode 100644 index 0000000..582b739 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/RELEASENOTES.md @@ -0,0 +1,207 @@ + +# Release Notes + +### 1.0.5 (Dec 07, 2016) +* [CB-11917](https://issues.apache.org/jira/browse/CB-11917) - Remove pull request template checklist item: "iCLA has been submitted…" +* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Incremented plugin version. +* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Updated version and RELEASENOTES.md for release 1.0.4 +* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to cordovaDependencies +* add JIRA issue tracker link +* Add badges for paramedic builds on Jenkins +* Add pull request template. +* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to README.md +* [CB-11091](https://issues.apache.org/jira/browse/CB-11091) Incremented plugin version. +* Updated version and RELEASENOTES.md for release 1.0.3 +* [CB-10720](https://issues.apache.org/jira/browse/CB-10720) Minor spelling/formatting changes. +* [CB-10636](https://issues.apache.org/jira/browse/CB-10636) Add JSHint for plugins +* chore: edit package.json license to match SPDX id +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Incremented plugin version. +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) linked issues in RELEASENOTES.md +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated version and RELEASENOTES.md for release 1.0.2 +* removed r prefix from tags +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated RELEASENOTES to be newest to oldest +* Actually fixing the contribute link. +* Fixing contribute link. +* Document formatting options for the console object +* [CB-5089](https://issues.apache.org/jira/browse/CB-5089) Document supported methods for console object +* reverted d58f218b9149d362ebb0b8ce697cf403569d14cd because logger is not needed on android +* remove travi-ci integration +* [CB-9192](https://issues.apache.org/jira/browse/CB-9192) Incremented plugin version. +* [CB-9202](https://issues.apache.org/jira/browse/CB-9202) updated repo url to github mirror in package.json +* [CB-9192](https://issues.apache.org/jira/browse/CB-9192) Updated version and RELEASENOTES.md for release 1.0.1 +* move logger.js and console-via-logger.js to common modules, instead of the numerous repeats that were there. +* clean up tests, info is below log level so it does not exist by default. +* add a couple tests +* [CB-9191](https://issues.apache.org/jira/browse/CB-9191) Add basic test +* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-console documentation translation: cordova-plugin-console +* attempt to fix npm markdown issue +* [CB-8858](https://issues.apache.org/jira/browse/CB-8858) Incremented plugin version. +* [CB-8858](https://issues.apache.org/jira/browse/CB-8858) Updated version in package.json for release 1.0.0 +* Revert "CB-8858 Incremented plugin version." +* [CB-8858](https://issues.apache.org/jira/browse/CB-8858) Incremented plugin version. +* [CB-8858](https://issues.apache.org/jira/browse/CB-8858) Updated version and RELEASENOTES.md for release 1.0.0 +* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) gave plugin major version bump +* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) changed plugin-id to pacakge-name +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id +* Use TRAVIS_BUILD_DIR, install paramedic by npm +* docs: renamed Windows8 to Windows +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) Updated Readme +* [CB-8560](https://issues.apache.org/jira/browse/CB-8560) Integrate TravisCI +* [CB-8438](https://issues.apache.org/jira/browse/CB-8438) cordova-plugin-console documentation translation: cordova-plugin-console +* [CB-8538](https://issues.apache.org/jira/browse/CB-8538) Added package.json file +* [CB-8362](https://issues.apache.org/jira/browse/CB-8362) Add Windows platform section to Console plugin +* [CB-8429](https://issues.apache.org/jira/browse/CB-8429) Incremented plugin version. +* [CB-8429](https://issues.apache.org/jira/browse/CB-8429) Updated version and RELEASENOTES.md for release 0.2.13 +* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) Use argumentForIndex rather than NSArray extension +* [CB-8110](https://issues.apache.org/jira/browse/CB-8110) Incremented plugin version. +* [CB-8110](https://issues.apache.org/jira/browse/CB-8110) Updated version and RELEASENOTES.md for release 0.2.12 +* [CB-7977](https://issues.apache.org/jira/browse/CB-7977) Mention deviceready in plugin docs +* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-console documentation translation: cordova-plugin-console +* [CB-7571](https://issues.apache.org/jira/browse/CB-7571) Incremented plugin version. +* [CB-7571](https://issues.apache.org/jira/browse/CB-7571) Updated version and RELEASENOTES.md for release 0.2.11 +* [CB-7249](https://issues.apache.org/jira/browse/CB-7249) cordova-plugin-console documentation translation: cordova-plugin-console +* [CB-7244](https://issues.apache.org/jira/browse/CB-7244) Incremented plugin version. +* [CB-7244](https://issues.apache.org/jira/browse/CB-7244) Updated version and RELEASENOTES.md for release 0.2.10 +* CB-7249cordova-plugin-console documentation translation: cordova-plugin-console +* CB-6127lisa6cordova-plugin-console documentation translation: cordova-plugin-console +* [CB-6877](https://issues.apache.org/jira/browse/CB-6877) Incremented plugin version. +* [CB-6877](https://issues.apache.org/jira/browse/CB-6877) Updated version and RELEASENOTES.md for release 0.2.9 +* [CB-6848](https://issues.apache.org/jira/browse/CB-6848) Add Android quirk, list applicable platforms +* [CB-6796](https://issues.apache.org/jira/browse/CB-6796) Add license +* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md +* [CB-6452](https://issues.apache.org/jira/browse/CB-6452) Incremented plugin version on dev branch. +* [CB-6452](https://issues.apache.org/jira/browse/CB-6452) Updated version and RELEASENOTES.md for release 0.2.8 +* [CB-6460](https://issues.apache.org/jira/browse/CB-6460) Update license headers +* Add NOTICE file +* [CB-5980](https://issues.apache.org/jira/browse/CB-5980) Incremented plugin version on dev branch. +* [CB-5980](https://issues.apache.org/jira/browse/CB-5980) Updated version and RELEASENOTES.md for release 0.2.7 +* Native console needs to be called DebugConsole to avoid ambiguous reference. This commit requires the 3.4.0 version of the native class factory +* [CB-4718](https://issues.apache.org/jira/browse/CB-4718) fixed Console plugin not work on wp +* [CB-5719](https://issues.apache.org/jira/browse/CB-5719) Incremented plugin version on dev branch. +* [CB-5719](https://issues.apache.org/jira/browse/CB-5719) Updated version and RELEASENOTES.md for release 0.2.6 +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Update license comment formatting of doc/index.md +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Add doc/index.md for Console plugin +* [CB-5565](https://issues.apache.org/jira/browse/CB-5565) Incremented plugin version on dev branch. +* [CB-5565](https://issues.apache.org/jira/browse/CB-5565) Updated version and RELEASENOTES.md for release 0.2.5 +* add ubuntu platform +* [CB-5188](https://issues.apache.org/jira/browse/CB-5188) +* [CB-5188](https://issues.apache.org/jira/browse/CB-5188) Updated version and RELEASENOTES.md for release 0.2.4 +* [CB-5154](https://issues.apache.org/jira/browse/CB-5154) log formatting incorrectly to native +* [CB-5128](https://issues.apache.org/jira/browse/CB-5128) added repo + issue tag to plugin.xml for console plugin +* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Incremented plugin version on dev branch. +* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Updated version and RELEASENOTES.md for release 0.2.3 +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) bumping&resetting version +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) renaming org.apache.cordova.core.console to org.apache.cordova.console +* Rename CHANGELOG.md -> RELEASENOTES.md +* [CB-4752](https://issues.apache.org/jira/browse/CB-4752) Incremented plugin version on dev branch. +* Add empty CHANGELOG.md +* [CB-4595](https://issues.apache.org/jira/browse/CB-4595) updated version +* reverted name element to be human readable +* updated name tag, namespace and readme +* [plugin.xml] standardizing license + meta +* [license] adding apache license file +* [Windows8] added support for windows8 [CB-4436](https://issues.apache.org/jira/browse/CB-4436) +* updating plugin.xml with registry data + +### 1.0.4 (Sep 08, 2016) +* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to `cordovaDependencies` +* add `JIRA` issue tracker link +* Add badges for paramedic builds on Jenkins +* Add pull request template. +* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to README.md + +### 1.0.3 (Apr 15, 2016) +* [CB-10720](https://issues.apache.org/jira/browse/CB-10720) Minor spelling/formatting changes. +* [CB-10636](https://issues.apache.org/jira/browse/CB-10636) Add `JSHint` for plugins + +### 1.0.2 (Nov 18, 2015) +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated `RELEASENOTES` to be newest to oldest +* Fixing contribute link. +* Document formatting options for the console object +* [CB-5089](https://issues.apache.org/jira/browse/CB-5089) Document supported methods for console object +* reverted `d58f218b9149d362ebb0b8ce697cf403569d14cd` because `logger` is not needed on **Android** + +### 1.0.1 (Jun 17, 2015) +* move logger.js and console-via-logger.js to common modules, instead of the numerous repeats that were there. +* clean up tests, info is below log level so it does not exist by default. +* add a couple tests +* [CB-9191](https://issues.apache.org/jira/browse/CB-9191) Add basic test +* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-console documentation translation: cordova-plugin-console +* attempt to fix npm markdown issue + +### 1.0.0 (Apr 15, 2015) +* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) gave plugin major version bump +* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) changed plugin-id to pacakge-name +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id +* Use TRAVIS_BUILD_DIR, install paramedic by npm +* docs: renamed Windows8 to Windows +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) Updated Readme +* [CB-8560](https://issues.apache.org/jira/browse/CB-8560) Integrate TravisCI +* [CB-8438](https://issues.apache.org/jira/browse/CB-8438) cordova-plugin-console documentation translation: cordova-plugin-console +* [CB-8538](https://issues.apache.org/jira/browse/CB-8538) Added package.json file +* [CB-8362](https://issues.apache.org/jira/browse/CB-8362) Add Windows platform section to Console plugin + +### 0.2.13 (Feb 04, 2015) +* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Use argumentForIndex rather than NSArray extension + +### 0.2.12 (Dec 02, 2014) +* [CB-7977](https://issues.apache.org/jira/browse/CB-7977) Mention `deviceready` in plugin docs +* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-console documentation translation: cordova-plugin-console + +### 0.2.11 (Sep 17, 2014) +* [CB-7249](https://issues.apache.org/jira/browse/CB-7249) cordova-plugin-console documentation translation + +### 0.2.10 (Aug 06, 2014) +* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Updated translations for docs + +### 0.2.9 (Jun 05, 2014) +* [CB-6848](https://issues.apache.org/jira/browse/CB-6848) Add Android quirk, list applicable platforms +* [CB-6796](https://issues.apache.org/jira/browse/CB-6796) Add license +* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md + +### 0.2.8 (Apr 17, 2014) +* [CB-6460](https://issues.apache.org/jira/browse/CB-6460): Update license headers +* Add NOTICE file + +### 0.2.7 (Feb 05, 2014) +* Native console needs to be called DebugConsole to avoid ambiguous reference. This commit requires the 3.4.0 version of the native class factory +* [CB-4718](https://issues.apache.org/jira/browse/CB-4718) fixed Console plugin not working on wp + +### 0.2.6 (Jan 02, 2014) +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Add doc/index.md for Console plugin + +### 0.2.5 (Dec 4, 2013) +* add ubuntu platform + +### 0.2.4 (Oct 28, 2013) +* [CB-5154](https://issues.apache.org/jira/browse/CB-5154) log formatting incorrectly to native +* [CB-5128](https://issues.apache.org/jira/browse/CB-5128): added repo + issue tag to plugin.xml for console plugin +* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Incremented plugin version on dev branch. + +### 0.2.3 (Sept 25, 2013) +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) bumping&resetting version +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) renaming org.apache.cordova.core.console to org.apache.cordova.console +* Rename CHANGELOG.md -> RELEASENOTES.md +* [CB-4752](https://issues.apache.org/jira/browse/CB-4752) Incremented plugin version on dev branch. + + diff --git a/mobile/plugins/cordova-plugin-console/doc/de/README.md b/mobile/plugins/cordova-plugin-console/doc/de/README.md new file mode 100644 index 0000000..933c1b7 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/de/README.md @@ -0,0 +1,43 @@ + + +# cordova-plugin-console + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg)](https://travis-ci.org/apache/cordova-plugin-console) + +Dieses Plugin stellt sicher, dass der Befehl console.log() so hilfreich ist, wie er sein kann. Es fügt zusätzliche Funktion für iOS, Ubuntu, Windows Phone 8 und Windows. Teilweise kann es vorkommen, dass der Befehl console.log() nicht korrekt erkannt wird, und es zu Fehlern bzw. zu nicht angezeigten Logs in der Console kommt. Wenn Sie mit der derzeitigen Funktionsweise zufrieden sind, kann es sein, dass Sie dieses Plugin nicht benötigen. + +Dieses Plugin wird ein global-`console`-Objekt definiert. + +Obwohl das Objekt im globalen Gültigkeitsbereich ist, stehen Features von diesem Plugin nicht bis nach dem `deviceready`-Ereignis. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## Installation + + cordova plugin add cordova-plugin-console + + +### Android Eigenarten + +Auf einigen Plattformen als Android fungieren console.log() auf mehrere Argumente wie console.log ("1", "2", "3"). Android wird jedoch nur auf das erste Argument fungieren. Nachfolgende Argumente zu console.log() werden ignoriert. Dieses Plugin ist nicht die Verantwortung dafür, es ist eine Einschränkung von Android selbst. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/doc/de/index.md b/mobile/plugins/cordova-plugin-console/doc/de/index.md new file mode 100644 index 0000000..9551782 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/de/index.md @@ -0,0 +1,41 @@ + + +# cordova-plugin-console + +Dieses Plugin stellt sicher, dass der Befehl console.log() so hilfreich ist, wie er sein kann. Es fügt zusätzliche Funktion für iOS, Ubuntu, Windows Phone 8 und Windows 8 hinzu. Teilweise kann es vorkommen, dass der Befehl console.log() nicht korrekt erkannt wird, und es zu Fehlern bzw. zu nicht angezeigten Logs in der Console kommt. Wenn Sie mit der derzeitigen Funktionsweise zufrieden sind, kann es sein, dass Sie dieses Plugin nicht benötigen. + +Dieses Plugin wird ein global-`console`-Objekt definiert. + +Obwohl das Objekt im globalen Gültigkeitsbereich ist, stehen Features von diesem Plugin nicht bis nach dem `deviceready`-Ereignis. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## Installation + + cordova plugin add cordova-plugin-console + + +### Android Eigenarten + +Auf einigen Plattformen als Android fungieren console.log() auf mehrere Argumente wie console.log ("1", "2", "3"). Android wird jedoch nur auf das erste Argument fungieren. Nachfolgende Argumente zu console.log() werden ignoriert. Dieses Plugin ist nicht die Verantwortung dafür, es ist eine Einschränkung von Android selbst. diff --git a/mobile/plugins/cordova-plugin-console/doc/es/README.md b/mobile/plugins/cordova-plugin-console/doc/es/README.md new file mode 100644 index 0000000..b089d63 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/es/README.md @@ -0,0 +1,41 @@ + + +# cordova-plugin-console + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg)](https://travis-ci.org/apache/cordova-plugin-console) + +Este plugin es para asegurarse de que console.log() es tan útil como puede ser. Agrega la función adicional para iOS, Ubuntu, Windows Phone 8 y Windows. Si estás contento con cómo funciona console.log() para ti, entonces probablemente no necesitas este plugin. + +Este plugin define un global `console` objeto. + +Aunque el objeto está en el ámbito global, características proporcionadas por este plugin no están disponibles hasta después de la `deviceready` evento. + + document.addEventListener ("deviceready", onDeviceReady, false); + function onDeviceReady() {console.log ("console.log funciona bien");} + + +## Instalación + + cordova plugin add cordova-plugin-console + + +### Rarezas Android + +En algunas plataformas que no sean Android, console.log() actuará en varios argumentos, como console.log ("1", "2", "3"). Sin embargo, Android actuará sólo en el primer argumento. Se omitirá posteriores argumentos para console.log(). Este plugin no es la causa de eso, es una limitación propia de Android. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/doc/es/index.md b/mobile/plugins/cordova-plugin-console/doc/es/index.md new file mode 100644 index 0000000..e6b8e68 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/es/index.md @@ -0,0 +1,39 @@ + + +# cordova-plugin-console + +Este plugin es para asegurarse de que console.log() es tan útil como puede ser. Añade función adicional para iOS, Windows Phone 8, Ubuntu y Windows 8. Si estás contento con cómo funciona console.log() para ti, entonces probablemente no necesitas este plugin. + +Este plugin define un global `console` objeto. + +Aunque el objeto está en el ámbito global, características proporcionadas por este plugin no están disponibles hasta después de la `deviceready` evento. + + document.addEventListener ("deviceready", onDeviceReady, false); + function onDeviceReady() {console.log ("console.log funciona bien");} + + +## Instalación + + Cordova plugin agregar cordova-plugin-console + + +### Rarezas Android + +En algunas plataformas que no sean Android, console.log() actuará en varios argumentos, como console.log ("1", "2", "3"). Sin embargo, Android actuará sólo en el primer argumento. Se omitirá posteriores argumentos para console.log(). Este plugin no es la causa de eso, es una limitación propia de Android. diff --git a/mobile/plugins/cordova-plugin-console/doc/fr/README.md b/mobile/plugins/cordova-plugin-console/doc/fr/README.md new file mode 100644 index 0000000..74207ac --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/fr/README.md @@ -0,0 +1,41 @@ + + +# cordova-plugin-console + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg)](https://travis-ci.org/apache/cordova-plugin-console) + +Ce plugin est destiné à faire en sorte que console.log() est aussi utile que possible. Il ajoute une fonction supplémentaire pour iOS, Ubuntu, Windows Phone 8 et Windows. Si vous êtes satisfait du fonctionnement de console.log() pour vous, alors vous avez probablement pas besoin ce plugin. + +Ce plugin définit un global `console` objet. + +Bien que l'objet est dans la portée globale, les fonctions offertes par ce plugin ne sont pas disponibles jusqu'après la `deviceready` événement. + + document.addEventListener (« deviceready », onDeviceReady, false) ; + function onDeviceReady() {console.log ("console.log fonctionne bien");} + + +## Installation + + cordova plugin add cordova-plugin-console + + +### Quirks Android + +Sur certaines plateformes autres que Android, console.log() va agir sur plusieurs arguments, tels que console.log ("1", "2", "3"). Toutefois, Android doit agir uniquement sur le premier argument. Les arguments suivants à console.log() seront ignorées. Ce plugin n'est pas la cause de cela, il s'agit d'une limitation d'Android lui-même. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/doc/fr/index.md b/mobile/plugins/cordova-plugin-console/doc/fr/index.md new file mode 100644 index 0000000..d0dbba5 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/fr/index.md @@ -0,0 +1,39 @@ + + +# cordova-plugin-console + +Ce plugin est destiné à faire en sorte que console.log() est aussi utile que possible. Il ajoute une fonction supplémentaire pour iOS, Ubuntu, Windows Phone 8 et Windows 8. Si vous êtes satisfait du fonctionnement de console.log() pour vous, alors vous avez probablement pas besoin ce plugin. + +Ce plugin définit un global `console` objet. + +Bien que l'objet est dans la portée globale, les fonctions offertes par ce plugin ne sont pas disponibles jusqu'après la `deviceready` événement. + + document.addEventListener (« deviceready », onDeviceReady, false) ; + function onDeviceReady() {console.log ("console.log fonctionne bien");} + + +## Installation + + Cordova plugin ajouter cordova-plugin-console + + +### Quirks Android + +Sur certaines plateformes autres que Android, console.log() va agir sur plusieurs arguments, tels que console.log ("1", "2", "3"). Toutefois, Android doit agir uniquement sur le premier argument. Les arguments suivants à console.log() seront ignorées. Ce plugin n'est pas la cause de cela, il s'agit d'une limitation d'Android lui-même. diff --git a/mobile/plugins/cordova-plugin-console/doc/it/README.md b/mobile/plugins/cordova-plugin-console/doc/it/README.md new file mode 100644 index 0000000..5394d55 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/it/README.md @@ -0,0 +1,43 @@ + + +# cordova-plugin-console + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg)](https://travis-ci.org/apache/cordova-plugin-console) + +Questo plugin è intesa a garantire che console.log() è tanto utile quanto può essere. Aggiunge una funzione aggiuntiva per iOS, Ubuntu, Windows Phone 8 e Windows. Se sei soddisfatto di come console.log() funziona per voi, quindi probabilmente non è necessario questo plugin. + +Questo plugin definisce un oggetto globale `console`. + +Sebbene l'oggetto sia in ambito globale, funzionalità fornite da questo plugin non sono disponibili fino a dopo l'evento `deviceready`. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## Installazione + + cordova plugin add cordova-plugin-console + + +### Stranezze Android + +Su alcune piattaforme diverse da Android, console.log() agirà su più argomenti, come ad esempio console ("1", "2", "3"). Tuttavia, Android agirà solo sul primo argomento. Argomenti successivi a console.log() verranno ignorati. Questo plugin non è la causa di ciò, è una limitazione di Android stesso. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/doc/it/index.md b/mobile/plugins/cordova-plugin-console/doc/it/index.md new file mode 100644 index 0000000..f0625b3 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/it/index.md @@ -0,0 +1,41 @@ + + +# cordova-plugin-console + +Questo plugin è intesa a garantire che console.log() è tanto utile quanto può essere. Aggiunge una funzione aggiuntiva per iOS, Ubuntu, Windows 8 e Windows Phone 8. Se sei soddisfatto di come console.log() funziona per voi, quindi probabilmente non è necessario questo plugin. + +Questo plugin definisce un oggetto globale `console`. + +Sebbene l'oggetto sia in ambito globale, funzionalità fornite da questo plugin non sono disponibili fino a dopo l'evento `deviceready`. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## Installazione + + cordova plugin add cordova-plugin-console + + +### Stranezze Android + +Su alcune piattaforme diverse da Android, console.log() agirà su più argomenti, come ad esempio console ("1", "2", "3"). Tuttavia, Android agirà solo sul primo argomento. Argomenti successivi a console.log() verranno ignorati. Questo plugin non è la causa di ciò, è una limitazione di Android stesso. diff --git a/mobile/plugins/cordova-plugin-console/doc/ja/README.md b/mobile/plugins/cordova-plugin-console/doc/ja/README.md new file mode 100644 index 0000000..059c373 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/ja/README.md @@ -0,0 +1,43 @@ + + +# cordova-plugin-console + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg)](https://travis-ci.org/apache/cordova-plugin-console) + +このプラグインは、その console.log() がすることができます便利なことを確認するものです。 それは iOS、Ubuntu、Windows Phone 8 は、Windows に追加の関数を追加します。 場合はあなたのための console.log() の作品に満足しているし、おそらく必要はありませんこのプラグイン。 + +このプラグインでは、グローバル ・ `console` オブジェクトを定義します。 + +オブジェクトは、グローバル スコープでですが、このプラグインによって提供される機能は、`deviceready` イベントの後まで使用できません。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## インストール + + cordova plugin add cordova-plugin-console + + +### Android の癖 + +アンドロイド以外のいくつかのプラットフォームで console.log() は console.log (「1」、「2」、「3」) など、複数の引数に動作します。 しかし、アンドロイドは、最初の引数でのみ動作します。 console.log() に後続の引数は無視されます。 このプラグインが原因ではない、それは Android の自体の制限です。 \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/doc/ja/index.md b/mobile/plugins/cordova-plugin-console/doc/ja/index.md new file mode 100644 index 0000000..413593c --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/ja/index.md @@ -0,0 +1,41 @@ + + +# cordova-plugin-console + +このプラグインは、その console.log() がすることができます便利なことを確認するものです。 それは、iOS、Ubuntu、Windows Phone 8 および Windows 8 の追加関数を追加します。 場合はあなたのための console.log() の作品に満足しているし、おそらく必要はありませんこのプラグイン。 + +このプラグインでは、グローバル ・ `console` オブジェクトを定義します。 + +オブジェクトは、グローバル スコープでですが、このプラグインによって提供される機能は、`deviceready` イベントの後まで使用できません。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## インストール + + cordova plugin add cordova-plugin-console + + +### Android の癖 + +アンドロイド以外のいくつかのプラットフォームで console.log() は console.log (「1」、「2」、「3」) など、複数の引数に動作します。 しかし、アンドロイドは、最初の引数でのみ動作します。 console.log() に後続の引数は無視されます。 このプラグインが原因ではない、それは Android の自体の制限です。 diff --git a/mobile/plugins/cordova-plugin-console/doc/ko/README.md b/mobile/plugins/cordova-plugin-console/doc/ko/README.md new file mode 100644 index 0000000..d03ee5a --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/ko/README.md @@ -0,0 +1,43 @@ + + +# cordova-plugin-console + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg)](https://travis-ci.org/apache/cordova-plugin-console) + +이 플러그인을 console.log()로 수 유용 되도록 의미입니다. 그것은 iOS, 우분투, Windows Phone 8, 및 창에 대 한 추가 기능을 추가합니다. Console.log() 당신을 위해 작동 하는 어떻게 행복 한 경우에, 그때 당신은 아마 필요 하지 않습니다이 플러그인. + +이 플러그인 글로벌 `console` 개체를 정의합니다. + +개체가 전역 범위에 있지만,이 플러그인에 의해 제공 되는 기능 하지 사용할 수 있습니다까지 `deviceready` 이벤트 후. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## 설치 + + cordova plugin add cordova-plugin-console + + +### 안 드 로이드 단점 + +안 드 로이드 이외의 일부 플랫폼에서 console.log() console.log ("1", "2", "3")와 같이 여러 인수에 작동할 것 이다. 그러나, 안 드 로이드는 첫 번째 인수에만 작동할 것 이다. Console.log() 후속 인수는 무시 됩니다. 이 플러그인의 원인이 되지 않습니다, 그리고 그것은 안 드 로이드 자체의 한계입니다. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/doc/ko/index.md b/mobile/plugins/cordova-plugin-console/doc/ko/index.md new file mode 100644 index 0000000..ca631e4 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/ko/index.md @@ -0,0 +1,41 @@ + + +# cordova-plugin-console + +이 플러그인을 console.log()로 수 유용 되도록 의미입니다. IOS, 우분투, Windows Phone 8 및 윈도우 8에 대 한 추가 기능을 추가 하 고 합니다. Console.log() 당신을 위해 작동 하는 어떻게 행복 한 경우에, 그때 당신은 아마 필요 하지 않습니다이 플러그인. + +이 플러그인 글로벌 `console` 개체를 정의합니다. + +개체가 전역 범위에 있지만,이 플러그인에 의해 제공 되는 기능 하지 사용할 수 있습니다까지 `deviceready` 이벤트 후. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## 설치 + + cordova plugin add cordova-plugin-console + + +### 안 드 로이드 단점 + +안 드 로이드 이외의 일부 플랫폼에서 console.log() console.log ("1", "2", "3")와 같이 여러 인수에 작동할 것 이다. 그러나, 안 드 로이드는 첫 번째 인수에만 작동할 것 이다. Console.log() 후속 인수는 무시 됩니다. 이 플러그인의 원인이 되지 않습니다, 그리고 그것은 안 드 로이드 자체의 한계입니다. diff --git a/mobile/plugins/cordova-plugin-console/doc/pl/README.md b/mobile/plugins/cordova-plugin-console/doc/pl/README.md new file mode 100644 index 0000000..78ab9d2 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/pl/README.md @@ -0,0 +1,43 @@ + + +# cordova-plugin-console + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg)](https://travis-ci.org/apache/cordova-plugin-console) + +Ten plugin jest przeznaczona do zapewnienia, że console.log() jest tak przydatne, jak to może być. To dodaje dodatkową funkcję dla iOS, Ubuntu, Windows Phone 8 i Windows. Jeśli jesteś zadowolony z jak console.log() pracuje dla Ciebie, wtedy prawdopodobnie nie potrzebują tej wtyczki. + +Ten plugin definiuje obiekt globalny `console`. + +Mimo, że obiekt jest w globalnym zasięgu, funkcji oferowanych przez ten plugin nie są dostępne dopiero po turnieju `deviceready`. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## Instalacja + + cordova plugin add cordova-plugin-console + + +### Dziwactwa Androida + +Na niektórych platformach innych niż Android console.log() będzie działać na wielu argumentów, takich jak console.log ("1", "2", "3"). Jednak Android będzie działać tylko na pierwszy argument. Kolejne argumenty do console.log() będą ignorowane. Ten plugin nie jest przyczyną, że, jest to ograniczenie Androida, sam. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/doc/pl/index.md b/mobile/plugins/cordova-plugin-console/doc/pl/index.md new file mode 100644 index 0000000..922b577 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/pl/index.md @@ -0,0 +1,41 @@ + + +# cordova-plugin-console + +Ten plugin jest przeznaczona do zapewnienia, że console.log() jest tak przydatne, jak to może być. To dodaje dodatkową funkcję dla iOS, Ubuntu, Windows Phone 8 i Windows 8. Jeśli jesteś zadowolony z jak console.log() pracuje dla Ciebie, wtedy prawdopodobnie nie potrzebują tej wtyczki. + +Ten plugin definiuje obiekt globalny `console`. + +Mimo, że obiekt jest w globalnym zasięgu, funkcji oferowanych przez ten plugin nie są dostępne dopiero po turnieju `deviceready`. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## Instalacja + + cordova plugin add cordova-plugin-console + + +### Dziwactwa Androida + +Na niektórych platformach innych niż Android console.log() będzie działać na wielu argumentów, takich jak console.log ("1", "2", "3"). Jednak Android będzie działać tylko na pierwszy argument. Kolejne argumenty do console.log() będą ignorowane. Ten plugin nie jest przyczyną, że, jest to ograniczenie Androida, sam. diff --git a/mobile/plugins/cordova-plugin-console/doc/ru/index.md b/mobile/plugins/cordova-plugin-console/doc/ru/index.md new file mode 100644 index 0000000..3cfe15d --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/ru/index.md @@ -0,0 +1,31 @@ + + +# cordova-plugin-console + +Этот плагин предназначен для обеспечения как полезным, поскольку это может быть что console.log(). Он добавляет дополнительные функции для iOS, Ubuntu, Windows Phone 8 и Windows 8. Если вы не довольны как console.log() работает для вас, то вы вероятно не нужен этот плагин. + +## Установка + + cordova plugin add cordova-plugin-console + + +### Особенности Android + +На некоторых платформах, отличных от Android console.log() будет действовать на нескольких аргументов, например console.log («1», «2», «3»). Тем не менее Android будет действовать только на первого аргумента. Последующие аргументы для console.log() будет игнорироваться. Этот плагин не является причиной этого, это ограничение Android сам. diff --git a/mobile/plugins/cordova-plugin-console/doc/zh/README.md b/mobile/plugins/cordova-plugin-console/doc/zh/README.md new file mode 100644 index 0000000..ce27c3e --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/zh/README.md @@ -0,0 +1,43 @@ + + +# cordova-plugin-console + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-console.svg)](https://travis-ci.org/apache/cordova-plugin-console) + +這個外掛程式是為了確保該 console.log() 是一樣有用,它可以是。 它將添加附加功能的 iOS,Ubuntu,Windows Phone 8 和視窗。 如果你是快樂與 console.log() 是如何為你工作,那麼可能不需要這個外掛程式。 + +這個外掛程式定義了一個全域 `console` 物件。 + +儘管物件是在全球範圍內,提供這個外掛程式的功能不可用直到 `deviceready` 事件之後。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## 安裝 + + cordova plugin add cordova-plugin-console + + +### Android 的怪癖 + +在一些平臺上除了 Android,console.log() 亦會根據多個參數,如 console.log ("1"、"2"、"3")。 然而,安卓系統只亦會根據第一個參數。 對 console.log() 的後續參數將被忽略。 這個外掛程式不是的原因,它是一個 android 作業系統本身的限制。 \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-console/doc/zh/index.md b/mobile/plugins/cordova-plugin-console/doc/zh/index.md new file mode 100644 index 0000000..e18a141 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/doc/zh/index.md @@ -0,0 +1,41 @@ + + +# cordova-plugin-console + +這個外掛程式是為了確保該 console.log() 是一樣有用,它可以是。 它將添加附加功能的 iOS、 Ubuntu,Windows Phone 8 和 Windows 8。 如果你是快樂與 console.log() 是如何為你工作,那麼可能不需要這個外掛程式。 + +這個外掛程式定義了一個全域 `console` 物件。 + +儘管物件是在全球範圍內,提供這個外掛程式的功能不可用直到 `deviceready` 事件之後。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log("console.log works well"); + } + + +## 安裝 + + cordova plugin add cordova-plugin-console + + +### Android 的怪癖 + +在一些平臺上除了 Android,console.log() 亦會根據多個參數,如 console.log ("1"、"2"、"3")。 然而,安卓系統只亦會根據第一個參數。 對 console.log() 的後續參數將被忽略。 這個外掛程式不是的原因,它是一個 android 作業系統本身的限制。 diff --git a/mobile/plugins/cordova-plugin-console/package.json b/mobile/plugins/cordova-plugin-console/package.json new file mode 100644 index 0000000..91ccc7c --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/package.json @@ -0,0 +1,47 @@ +{ + "name": "cordova-plugin-console", + "version": "1.0.5", + "description": "Cordova Console Plugin", + "cordova": { + "id": "cordova-plugin-console", + "platforms": [ + "ios", + "ubuntu", + "wp7", + "wp8", + "windows8", + "windows" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/apache/cordova-plugin-console" + }, + "keywords": [ + "cordova", + "console", + "ecosystem:cordova", + "cordova-ios", + "cordova-ubuntu", + "cordova-wp7", + "cordova-wp8", + "cordova-windows8", + "cordova-windows" + ], + "scripts": { + "test": "npm run jshint", + "jshint": "node node_modules/jshint/bin/jshint www && node node_modules/jshint/bin/jshint src && node node_modules/jshint/bin/jshint tests" + }, + "author": "Apache Software Foundation", + "license": "Apache-2.0", + "engines": { + "cordovaDependencies": { + "2.0.0": { + "cordova": ">100" + } + } + }, + "devDependencies": { + "jshint": "^2.6.0" + } +} diff --git a/mobile/plugins/cordova-plugin-console/plugin.xml b/mobile/plugins/cordova-plugin-console/plugin.xml new file mode 100644 index 0000000..114c665 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/plugin.xml @@ -0,0 +1,127 @@ + + + + + + Console + Cordova Console Plugin + Apache 2.0 + cordova,console + https://git-wip-us.apache.org/repos/asf/cordova-plugin-console.git + https://issues.apache.org/jira/browse/CB/component/12320644 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/plugins/cordova-plugin-console/src/ios/CDVLogger.h b/mobile/plugins/cordova-plugin-console/src/ios/CDVLogger.h new file mode 100644 index 0000000..7cfb306 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/src/ios/CDVLogger.h @@ -0,0 +1,26 @@ +/* + 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. + */ + +#import + +@interface CDVLogger : CDVPlugin + +- (void)logLevel:(CDVInvokedUrlCommand*)command; + +@end diff --git a/mobile/plugins/cordova-plugin-console/src/ios/CDVLogger.m b/mobile/plugins/cordova-plugin-console/src/ios/CDVLogger.m new file mode 100644 index 0000000..ccfa3a5 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/src/ios/CDVLogger.m @@ -0,0 +1,38 @@ +/* + 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. + */ + +#import "CDVLogger.h" +#import + +@implementation CDVLogger + +/* log a message */ +- (void)logLevel:(CDVInvokedUrlCommand*)command +{ + id level = [command argumentAtIndex:0]; + id message = [command argumentAtIndex:1]; + + if ([level isEqualToString:@"LOG"]) { + NSLog(@"%@", message); + } else { + NSLog(@"%@: %@", level, message); + } +} + +@end diff --git a/mobile/plugins/cordova-plugin-console/src/ubuntu/console.cpp b/mobile/plugins/cordova-plugin-console/src/ubuntu/console.cpp new file mode 100644 index 0000000..9de09f4 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/src/ubuntu/console.cpp @@ -0,0 +1,29 @@ +/* + * Licensed 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. + */ + +#include "console.h" + +#include + +Console::Console(Cordova *cordova) : CPlugin(cordova) { +} + +void Console::logLevel(int scId, int ecId, QString level, QString message) { + Q_UNUSED(scId) + Q_UNUSED(ecId) + + if (level != "LOG") + std::cout << "[" << level.toStdString() << "] "; + std::cout << message.toStdString() << std::endl; +} diff --git a/mobile/plugins/cordova-plugin-console/src/ubuntu/console.h b/mobile/plugins/cordova-plugin-console/src/ubuntu/console.h new file mode 100644 index 0000000..3f3d163 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/src/ubuntu/console.h @@ -0,0 +1,43 @@ +/* + * Licensed 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. + */ + +#ifndef CONSOLE_H_FDSVCXGFRS +#define CONSOLE_H_FDSVCXGFRS + +#include + +#include + +class Console : public CPlugin { + Q_OBJECT +public: + explicit Console(Cordova *cordova); + + virtual const QString fullName() override { + return Console::fullID(); + } + + virtual const QString shortName() override { + return "Console"; + } + + static const QString fullID() { + return "Console"; + } + +public slots: + void logLevel(int scId, int ecId, QString level, QString message); +}; + +#endif diff --git a/mobile/plugins/cordova-plugin-console/src/wp/DebugConsole.cs b/mobile/plugins/cordova-plugin-console/src/wp/DebugConsole.cs new file mode 100644 index 0000000..9bb5476 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/src/wp/DebugConsole.cs @@ -0,0 +1,47 @@ +/* + Licensed 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. +*/ + +using System; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using System.Diagnostics; + +namespace WPCordovaClassLib.Cordova.Commands +{ + public class DebugConsole : BaseCommand + { + public void logLevel(string options) + { + string[] args = JSON.JsonHelper.Deserialize(options); + string level = args[0]; + string msg = args[1]; + + if (level.Equals("LOG")) + { + Debug.WriteLine(msg); + } + else + { + Debug.WriteLine(level + ": " + msg); + } + } + } +} diff --git a/mobile/plugins/cordova-plugin-console/tests/plugin.xml b/mobile/plugins/cordova-plugin-console/tests/plugin.xml new file mode 100644 index 0000000..da47af4 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/tests/plugin.xml @@ -0,0 +1,31 @@ + + + + + Cordova Console Plugin Tests + Apache 2.0 + + + + diff --git a/mobile/plugins/cordova-plugin-console/tests/tests.js b/mobile/plugins/cordova-plugin-console/tests/tests.js new file mode 100644 index 0000000..74765d9 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/tests/tests.js @@ -0,0 +1,43 @@ +/* + * + * 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. + * +*/ + +/* jshint jasmine: true */ + +exports.defineAutoTests = function () { + describe("Console", function () { + it("console.spec.1 should exist", function() { + expect(window.console).toBeDefined(); + }); + + it("console.spec.2 has required methods log|warn|error", function(){ + expect(window.console.log).toBeDefined(); + expect(typeof window.console.log).toBe('function'); + + expect(window.console.warn).toBeDefined(); + expect(typeof window.console.warn).toBe('function'); + + expect(window.console.error).toBeDefined(); + expect(typeof window.console.error).toBe('function'); + }); + }); +}; + +exports.defineManualTests = function (contentEl, createActionButton) {}; diff --git a/mobile/plugins/cordova-plugin-console/www/console-via-logger.js b/mobile/plugins/cordova-plugin-console/www/console-via-logger.js new file mode 100644 index 0000000..ffee326 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/www/console-via-logger.js @@ -0,0 +1,186 @@ +/* + * + * 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. + * +*/ + +//------------------------------------------------------------------------------ + +var logger = require("./logger"); + +//------------------------------------------------------------------------------ +// object that we're exporting +//------------------------------------------------------------------------------ +var console = module.exports; + +//------------------------------------------------------------------------------ +// copy of the original console object +//------------------------------------------------------------------------------ +var WinConsole = window.console; + +//------------------------------------------------------------------------------ +// whether to use the logger +//------------------------------------------------------------------------------ +var UseLogger = false; + +//------------------------------------------------------------------------------ +// Timers +//------------------------------------------------------------------------------ +var Timers = {}; + +//------------------------------------------------------------------------------ +// used for unimplemented methods +//------------------------------------------------------------------------------ +function noop() {} + +//------------------------------------------------------------------------------ +// used for unimplemented methods +//------------------------------------------------------------------------------ +console.useLogger = function (value) { + if (arguments.length) UseLogger = !!value; + + if (UseLogger) { + if (logger.useConsole()) { + throw new Error("console and logger are too intertwingly"); + } + } + + return UseLogger; +}; + +//------------------------------------------------------------------------------ +console.log = function() { + if (logger.useConsole()) return; + logger.log.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.error = function() { + if (logger.useConsole()) return; + logger.error.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.warn = function() { + if (logger.useConsole()) return; + logger.warn.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.info = function() { + if (logger.useConsole()) return; + logger.info.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.debug = function() { + if (logger.useConsole()) return; + logger.debug.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.assert = function(expression) { + if (expression) return; + + var message = logger.format.apply(logger.format, [].slice.call(arguments, 1)); + console.log("ASSERT: " + message); +}; + +//------------------------------------------------------------------------------ +console.clear = function() {}; + +//------------------------------------------------------------------------------ +console.dir = function(object) { + console.log("%o", object); +}; + +//------------------------------------------------------------------------------ +console.dirxml = function(node) { + console.log(node.innerHTML); +}; + +//------------------------------------------------------------------------------ +console.trace = noop; + +//------------------------------------------------------------------------------ +console.group = console.log; + +//------------------------------------------------------------------------------ +console.groupCollapsed = console.log; + +//------------------------------------------------------------------------------ +console.groupEnd = noop; + +//------------------------------------------------------------------------------ +console.time = function(name) { + Timers[name] = new Date().valueOf(); +}; + +//------------------------------------------------------------------------------ +console.timeEnd = function(name) { + var timeStart = Timers[name]; + if (!timeStart) { + console.warn("unknown timer: " + name); + return; + } + + var timeElapsed = new Date().valueOf() - timeStart; + console.log(name + ": " + timeElapsed + "ms"); +}; + +//------------------------------------------------------------------------------ +console.timeStamp = noop; + +//------------------------------------------------------------------------------ +console.profile = noop; + +//------------------------------------------------------------------------------ +console.profileEnd = noop; + +//------------------------------------------------------------------------------ +console.count = noop; + +//------------------------------------------------------------------------------ +console.exception = console.log; + +//------------------------------------------------------------------------------ +console.table = function(data, columns) { + console.log("%o", data); +}; + +//------------------------------------------------------------------------------ +// return a new function that calls both functions passed as args +//------------------------------------------------------------------------------ +function wrappedOrigCall(orgFunc, newFunc) { + return function() { + var args = [].slice.call(arguments); + try { orgFunc.apply(WinConsole, args); } catch (e) {} + try { newFunc.apply(console, args); } catch (e) {} + }; +} + +//------------------------------------------------------------------------------ +// For every function that exists in the original console object, that +// also exists in the new console object, wrap the new console method +// with one that calls both +//------------------------------------------------------------------------------ +for (var key in console) { + if (typeof WinConsole[key] == "function") { + console[key] = wrappedOrigCall(WinConsole[key], console[key]); + } +} diff --git a/mobile/plugins/cordova-plugin-console/www/logger.js b/mobile/plugins/cordova-plugin-console/www/logger.js new file mode 100644 index 0000000..430d887 --- /dev/null +++ b/mobile/plugins/cordova-plugin-console/www/logger.js @@ -0,0 +1,354 @@ +/* + * + * 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. + * +*/ + +//------------------------------------------------------------------------------ +// The logger module exports the following properties/functions: +// +// LOG - constant for the level LOG +// ERROR - constant for the level ERROR +// WARN - constant for the level WARN +// INFO - constant for the level INFO +// DEBUG - constant for the level DEBUG +// logLevel() - returns current log level +// logLevel(value) - sets and returns a new log level +// useConsole() - returns whether logger is using console +// useConsole(value) - sets and returns whether logger is using console +// log(message,...) - logs a message at level LOG +// error(message,...) - logs a message at level ERROR +// warn(message,...) - logs a message at level WARN +// info(message,...) - logs a message at level INFO +// debug(message,...) - logs a message at level DEBUG +// logLevel(level,message,...) - logs a message specified level +// +//------------------------------------------------------------------------------ + +var logger = exports; + +var exec = require('cordova/exec'); + +var UseConsole = false; +var UseLogger = true; +var Queued = []; +var DeviceReady = false; +var CurrentLevel; + +var originalConsole = console; + +/** + * Logging levels + */ + +var Levels = [ + "LOG", + "ERROR", + "WARN", + "INFO", + "DEBUG" +]; + +/* + * add the logging levels to the logger object and + * to a separate levelsMap object for testing + */ + +var LevelsMap = {}; +for (var i=0; i 0){ + formatArgs.unshift(fmtString); // add formatString + } + + var message = logger.format.apply(logger.format, formatArgs); + + if (LevelsMap[level] === null) { + throw new Error("invalid logging level: " + level); + } + + if (LevelsMap[level] > CurrentLevel) return; + + // queue the message if not yet at deviceready + if (!DeviceReady && !UseConsole) { + Queued.push([level, message]); + return; + } + + // Log using the native logger if that is enabled + if (UseLogger) { + exec(null, null, "Console", "logLevel", [level, message]); + } + + // Log using the console if that is enabled + if (UseConsole) { + // make sure console is not using logger + if (console.useLogger()) { + throw new Error("console and logger are too intertwingly"); + } + + // log to the console + switch (level) { + case logger.LOG: originalConsole.log(message); break; + case logger.ERROR: originalConsole.log("ERROR: " + message); break; + case logger.WARN: originalConsole.log("WARN: " + message); break; + case logger.INFO: originalConsole.log("INFO: " + message); break; + case logger.DEBUG: originalConsole.log("DEBUG: " + message); break; + } + } +}; + + +/** + * Formats a string and arguments following it ala console.log() + * + * Any remaining arguments will be appended to the formatted string. + * + * for rationale, see FireBug's Console API: + * http://getfirebug.com/wiki/index.php/Console_API + */ +logger.format = function(formatString, args) { + return __format(arguments[0], [].slice.call(arguments,1)).join(' '); +}; + + +//------------------------------------------------------------------------------ +/** + * Formats a string and arguments following it ala vsprintf() + * + * format chars: + * %j - format arg as JSON + * %o - format arg as JSON + * %c - format arg as '' + * %% - replace with '%' + * any other char following % will format it's + * arg via toString(). + * + * Returns an array containing the formatted string and any remaining + * arguments. + */ +function __format(formatString, args) { + if (formatString === null || formatString === undefined) return [""]; + if (arguments.length == 1) return [formatString.toString()]; + + if (typeof formatString != "string") + formatString = formatString.toString(); + + var pattern = /(.*?)%(.)(.*)/; + var rest = formatString; + var result = []; + + while (args.length) { + var match = pattern.exec(rest); + if (!match) break; + + var arg = args.shift(); + rest = match[3]; + result.push(match[1]); + + if (match[2] == '%') { + result.push('%'); + args.unshift(arg); + continue; + } + + result.push(__formatted(arg, match[2])); + } + + result.push(rest); + + var remainingArgs = [].slice.call(args); + remainingArgs.unshift(result.join('')); + return remainingArgs; +} + +function __formatted(object, formatChar) { + + try { + switch(formatChar) { + case 'j': + case 'o': return JSON.stringify(object); + case 'c': return ''; + } + } + catch (e) { + return "error JSON.stringify()ing argument: " + e; + } + + if ((object === null) || (object === undefined)) { + return Object.prototype.toString.call(object); + } + + return object.toString(); +} + + +//------------------------------------------------------------------------------ +// when deviceready fires, log queued messages +logger.__onDeviceReady = function() { + if (DeviceReady) return; + + DeviceReady = true; + + for (var i=0; i + +# Contributing to Apache Cordova + +Anyone can contribute to Cordova. And we need your contributions. + +There are multiple ways to contribute: report bugs, improve the docs, and +contribute code. + +For instructions on this, start with the +[contribution overview](http://cordova.apache.org/contribute/). + +The details are explained there, but the important items are: + - Sign and submit an Apache ICLA (Contributor License Agreement). + - Have a Jira issue open that corresponds to your contribution. + - Run the tests so your patch doesn't break existing functionality. + +We look forward to your contributions! diff --git a/mobile/plugins/cordova-plugin-device/LICENSE b/mobile/plugins/cordova-plugin-device/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/NOTICE b/mobile/plugins/cordova-plugin-device/NOTICE new file mode 100644 index 0000000..8ec56a5 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/NOTICE @@ -0,0 +1,5 @@ +Apache Cordova +Copyright 2012 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). diff --git a/mobile/plugins/cordova-plugin-device/README.md b/mobile/plugins/cordova-plugin-device/README.md new file mode 100644 index 0000000..10b8016 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/README.md @@ -0,0 +1,311 @@ +--- +title: Device +description: Get device information. +--- + + +|Android|iOS| Windows 8.1 Store | Windows 8.1 Phone | Windows 10 Store | Travis CI | +|:-:|:-:|:-:|:-:|:-:|:-:| +|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-device)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-device/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-device)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-device/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-device)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-device/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-device)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-device/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-device)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-device/)|[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device)| + +# cordova-plugin-device + +This plugin defines a global `device` object, which describes the device's hardware and software. +Although the object is in the global scope, it is not available until after the `deviceready` event. + +```js +document.addEventListener("deviceready", onDeviceReady, false); +function onDeviceReady() { + console.log(device.cordova); +} +``` + +Report issues with this plugin on the [Apache Cordova issue tracker](https://issues.apache.org/jira/issues/?jql=project%20%3D%20CB%20AND%20status%20in%20%28Open%2C%20%22In%20Progress%22%2C%20Reopened%29%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20%22Plugin%20Device%22%20ORDER%20BY%20priority%20DESC%2C%20summary%20ASC%2C%20updatedDate%20DESC) + + +## Installation + + cordova plugin add cordova-plugin-device + +## Properties + +- device.cordova +- device.model +- device.platform +- device.uuid +- device.version +- device.manufacturer +- device.isVirtual +- device.serial + +## device.cordova + +Get the version of Cordova running on the device. + +### Supported Platforms + +- Amazon Fire OS +- Android +- BlackBerry 10 +- Browser +- Firefox OS +- iOS +- Tizen +- Windows Phone 7 and 8 +- Windows +- OSX + +## device.model + +The `device.model` returns the name of the device's model or +product. The value is set by the device manufacturer and may be +different across versions of the same product. + +### Supported Platforms + +- Android +- BlackBerry 10 +- Browser +- iOS +- Tizen +- Windows Phone 7 and 8 +- Windows +- OSX + +### Quick Example + +```js +// Android: Nexus One returns "Passion" (Nexus One code name) +// Motorola Droid returns "voles" +// BlackBerry: Torch 9800 returns "9800" +// Browser: Google Chrome returns "Chrome" +// Safari returns "Safari" +// iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. See http://theiphonewiki.com/wiki/index.php?title=Models +// OSX: returns "x86_64" +// +var model = device.model; +``` + +### Android Quirks + +- Gets the [product name](http://developer.android.com/reference/android/os/Build.html#PRODUCT) instead of the [model name](http://developer.android.com/reference/android/os/Build.html#MODEL), which is often the production code name. For example, the Nexus One returns `Passion`, and Motorola Droid returns `voles`. + +### Tizen Quirks + +- Returns the device model assigned by the vendor, for example, `TIZEN` + +### Windows Phone 7 and 8 Quirks + +- Returns the device model specified by the manufacturer. For example, the Samsung Focus returns `SGH-i917`. + +## device.platform + +Get the device's operating system name. + +```js +var string = device.platform; +``` +### Supported Platforms + +- Android +- BlackBerry 10 +- Browser +- Firefox OS +- iOS +- Tizen +- Windows Phone 7 and 8 +- Windows +- OSX + +### Quick Example + +```js +// Depending on the device, a few examples are: +// - "Android" +// - "BlackBerry 10" +// - "browser" +// - "iOS" +// - "WinCE" +// - "Tizen" +// - "Mac OS X" +var devicePlatform = device.platform; +``` + +### Windows Phone 7 Quirks + +Windows Phone 7 devices report the platform as `WinCE`. + +### Windows Phone 8 Quirks + +Windows Phone 8 devices report the platform as `Win32NT`. + +## device.uuid + +Get the device's Universally Unique Identifier ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier)). + +```js +var string = device.uuid; +``` + +### Description + +The details of how a UUID is generated are determined by the device manufacturer and are specific to the device's platform or model. + +### Supported Platforms + +- Android +- BlackBerry 10 +- iOS +- Tizen +- Windows Phone 7 and 8 +- Windows +- OSX + +### Quick Example + +```js +// Android: Returns a random 64-bit integer (as a string, again!) +// The integer is generated on the device's first boot +// +// BlackBerry: Returns the PIN number of the device +// This is a nine-digit unique integer (as a string, though!) +// +// iPhone: (Paraphrased from the UIDevice Class documentation) +// Returns the [UIDevice identifierForVendor] UUID which is unique and the same for all apps installed by the same vendor. However the UUID can be different if the user deletes all apps from the vendor and then reinstalls it. +// Windows Phone 7 : Returns a hash of device+current user, +// if the user is not defined, a guid is generated and will persist until the app is uninstalled +// Tizen: returns the device IMEI (International Mobile Equipment Identity or IMEI is a number +// unique to every GSM and UMTS mobile phone. +var deviceID = device.uuid; +``` + +### iOS Quirk + +The `uuid` on iOS uses the identifierForVendor property. It is unique to the device across the same vendor, but will be different for different vendors and will change if all apps from the vendor are deleted and then reinstalled. +Refer [here](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIDevice_Class/#//apple_ref/occ/instp/UIDevice/identifierForVendor) for details. +The UUID will be the same if app is restored from a backup or iCloud as it is saved in preferences. Users using older versions of this plugin will still receive the same previous UUID generated by another means as it will be retrieved from preferences. + +### OSX Quirk + +The `uuid` on OSX is generated automatically if it does not exist yet and is stored in the `standardUserDefaults` in the `CDVUUID` property. + +### Windows Phone 7 and 8 Quirks + +The `uuid` for Windows Phone 7 requires the permission +`ID_CAP_IDENTITY_DEVICE`. Microsoft will likely deprecate this +property soon. If the capability is not available, the application +generates a persistent guid that is maintained for the duration of the +application's installation on the device. + +## device.version + +Get the operating system version. + + var string = device.version; + +### Supported Platforms + +- Android 2.1+ +- BlackBerry 10 +- Browser +- iOS +- Tizen +- Windows Phone 7 and 8 +- Windows +- OSX + +### Quick Example + +```js +// Android: Froyo OS would return "2.2" +// Eclair OS would return "2.1", "2.0.1", or "2.0" +// Version can also return update level "2.1-update1" +// +// BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" +// +// Browser: Returns version number for the browser +// +// iPhone: iOS 3.2 returns "3.2" +// +// Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 +// Windows 8: return the current OS version, ex on Windows 8.1 returns 6.3.9600.16384 +// Tizen: returns "TIZEN_20120425_2" +// OSX: El Capitan would return "10.11.2" +// +var deviceVersion = device.version; +``` + +## device.manufacturer + +Get the device's manufacturer. + + var string = device.manufacturer; + +### Supported Platforms + +- Android +- BlackBerry 10 +- iOS +- Windows Phone 7 and 8 +- Windows + +### Quick Example + +```js +// Android: Motorola XT1032 would return "motorola" +// BlackBerry: returns "BlackBerry" +// iPhone: returns "Apple" +// +var deviceManufacturer = device.manufacturer; +``` + +## device.isVirtual + +whether the device is running on a simulator. + +```js +var isSim = device.isVirtual; +``` + +### Supported Platforms + +- Android 2.1+ +- iOS +- Windows Phone 8 +- Windows +- OSX + +### OSX Quirk + +The `isVirtual` property on OS X always returns false. + +## device.serial + +Get the device hardware serial number ([SERIAL](http://developer.android.com/reference/android/os/Build.html#SERIAL)). + +```js +var string = device.serial; +``` + +### Supported Platforms + +- Android +- OSX + diff --git a/mobile/plugins/cordova-plugin-device/RELEASENOTES.md b/mobile/plugins/cordova-plugin-device/RELEASENOTES.md new file mode 100644 index 0000000..c06a44c --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/RELEASENOTES.md @@ -0,0 +1,333 @@ + +# Release Notes + +### 1.1.4 (Dec 07, 2016) +* [CB-11917](https://issues.apache.org/jira/browse/CB-11917) - Remove pull request template checklist item: "iCLA has been submitted…" +* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Incremented plugin version. +* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Updated version and RELEASENOTES.md for release 1.1.3 +* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to cordovaDependencies +* Add badges for paramedic builds on Jenkins +* Add pull request template. +* Readme: Add fenced code blocks with langauage hints +* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to README.md +* [CB-11091](https://issues.apache.org/jira/browse/CB-11091) Incremented plugin version. +* Updated version and RELEASENOTES.md for release 1.1.2 +* Close #49 +* Use passed device, follow create policy forf CFUUIDCreate +* [CB-10631](https://issues.apache.org/jira/browse/CB-10631) ios: Fix for device.uuid in iOS 5.1.1 +* Updating the comment to exclude URL +* Minor changes to readme +* [CB-10636](https://issues.apache.org/jira/browse/CB-10636) Add JSHint for plugins +* chore: edit package.json license to match SPDX id +* Refactored deviceInfo on iOS for better readability. +* [CB-10368](https://issues.apache.org/jira/browse/CB-10368) Incremented plugin version. +* [CB-10368](https://issues.apache.org/jira/browse/CB-10368) Updated version and RELEASENOTES.md for release 1.1.1 +* Property manufacturer documented +* fix typo +* [CB-10238](https://issues.apache.org/jira/browse/CB-10238) Move device-plugin out from cordovalib to the plugin repository +* [CB-10238](https://issues.apache.org/jira/browse/CB-10238) Move device-plugin out from cordovalib to the plugin repository +* [CB-9923](https://issues.apache.org/jira/browse/CB-9923) Update `device.platform` documentation for browser platform +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Incremented plugin version. +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) linked issues in RELEASENOTES.md +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated version and RELEASENOTES.md for release 1.1.0 +* removed r prefix from tags +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated RELEASENOTES to be newest to oldest +* fix whitespace tab to spaces +* Add `isVirtual` for Windows 8.x (Phone) platforms +* [CB-9847](https://issues.apache.org/jira/browse/CB-9847) Fixed merge error of 408c3a20be976ca5b814c9f161c31d4edf1c00fc +* Added basic Android support for hardware serial number +* Cleanup PRs. This closes #27. This closes #17. +* [CB-9865](https://issues.apache.org/jira/browse/CB-9865) Better simulator detection for iOS +* Actually fixing the contribute link. +* Fixing contribute link. +* fix merge conflict, for reals +* add JIRA issue tracker link +* updated docs +* Cleanup wp8 code +* WP8 implementation +* update to use TARGET_OS_SIMULATOR as TARGET_IPHONE_SIMULATOR is deprecated. +* update code to use 'isVirtual' +* create test to verify existence and type of new property 'isVirtual' +* add isSimulator for iOS & Android device +* Fixed typo +* Updated documentation to mention backwards compatibility +* Updated README to reflect new behaviour and quirks on iOS +* Check user defaults first to maintain backwards compatibility +* Revert "Check user defaults first to maintain backwards compatibility" +* Check user defaults first to maintain backwards compatibility +* Remove line incorrectly committed +* Changed UUID to use [UIDevice identifierForVendor] +* remove travis-ci +* [CB-9192](https://issues.apache.org/jira/browse/CB-9192) Incremented plugin version. +* [CB-9202](https://issues.apache.org/jira/browse/CB-9202) updated repo url to github mirror in package.json +* [CB-9192](https://issues.apache.org/jira/browse/CB-9192) Updated version and RELEASENOTES.md for release 1.0.1 +* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-device documentation translation: cordova-plugin-device +* Attempts to corrent npm markdown issue +* [CB-8858](https://issues.apache.org/jira/browse/CB-8858) Incremented plugin version. +* [CB-8858](https://issues.apache.org/jira/browse/CB-8858) Updated version in package.json for release 1.0.0 +* Revert "CB-8858 Incremented plugin version." +* [CB-8858](https://issues.apache.org/jira/browse/CB-8858) Incremented plugin version. +* [CB-8858](https://issues.apache.org/jira/browse/CB-8858) Updated version and RELEASENOTES.md for release 1.0.0 +* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) gave plugin major version bump +* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) changed plugin-id to pacakge-name +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) properly updated translated docs to use new id +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id +* Use TRAVIS_BUILD_DIR, install paramedic by npm +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) Updated Readme +* remove defunct windows8 version +* add travis badge +* update plugin path +* Add cross-plugin ios paramedic test running for TravisCI +* [CB-8538](https://issues.apache.org/jira/browse/CB-8538) Added package.json file +* [CB-8429](https://issues.apache.org/jira/browse/CB-8429) Incremented plugin version. +* [CB-8429](https://issues.apache.org/jira/browse/CB-8429) Updated version and RELEASENOTES.md for release 0.3.0 +* Fixes a syntax error introduced in 1a13ee0 +* [CB7285][Windows] add manufacturer property for windows, and cleanup +* [CB-7285](https://issues.apache.org/jira/browse/CB-7285) Add test for manufacturer property +* [CB-7285][WP8] add manufacturer info +* update of manufacturer name +* added device.manufacturer property for Android, iOS (Apple duh), Blackberry (RIM duh) +* Support for Windows Phone 8 ANID2 ANID is only supported up to Windows Phone 7.5 +* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) Use a local copy of uniqueAppInstanceIdentifier rather than CordovaLib's version +* - Fixed a bug that caused an "cannot call method of undefined" error if the browser's user agent wasn't recognized - Added support for Internet Explorer user agent strings - NOTE: IE 11's user agent string does not include "MSIE", so "Trident" is searched for instead +* [CB-8110](https://issues.apache.org/jira/browse/CB-8110) Incremented plugin version. +* [CB-8110](https://issues.apache.org/jira/browse/CB-8110) Updated version and RELEASENOTES.md for release 0.2.13 +* Changing device.platform to always report the platform as "browser". +* [CB-5892](https://issues.apache.org/jira/browse/CB-5892) - Remove deprecated window.Settings +* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-device documentation translation: cordova-plugin-device +* [CB-7571](https://issues.apache.org/jira/browse/CB-7571) Bump version of nested plugin to match parent plugin +* [CB-7571](https://issues.apache.org/jira/browse/CB-7571) Incremented plugin version. +* [CB-7571](https://issues.apache.org/jira/browse/CB-7571) Updated version and RELEASENOTES.md for release 0.2.12 +* [CB-7471](https://issues.apache.org/jira/browse/CB-7471) cordova-plugin-device documentation translation: cordova-plugin-device +* [CB-7552](https://issues.apache.org/jira/browse/CB-7552) - device.name docs have not been removed +* [fxos] Fix cordova version +* added status box and documentation to manual tests +* [fxos] Fix cordova version +* added status box and documentation to manual tests +* Added plugin support for the browser +* [CB-7262](https://issues.apache.org/jira/browse/CB-7262) Adds support for universal windows apps. +* [CB-7244](https://issues.apache.org/jira/browse/CB-7244) Incremented plugin version. +* [CB-7244](https://issues.apache.org/jira/browse/CB-7244) Updated version and RELEASENOTES.md for release 0.2.11 +* update DeviceProxy.js +* [CB-7168](https://issues.apache.org/jira/browse/CB-7168) Moving Device autotests to plugin (aka new-style tests) +* CB-6127lisa7cordova-plugin-consolecordova-plugin-device documentation translation: cordova-plugin-device +* Use Windows system calls to get better info +* [CB-6877](https://issues.apache.org/jira/browse/CB-6877) Incremented plugin version. +* [CB-6877](https://issues.apache.org/jira/browse/CB-6877) Updated version and RELEASENOTES.md for release 0.2.10 +* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Spanish and French Translations added. Github close #12 +* Changing 1.5 to 2.0 +* added firefoxos version - conversion +* added firefoxos version +* [CB-6800](https://issues.apache.org/jira/browse/CB-6800) Add license +* documentation translation: cordova-plugin-device +* Lisa testing pulling in plugins for plugin: cordova-plugin-device +* Lisa testing pulling in plugins for plugin: cordova-plugin-device +* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md +* [CB-6452](https://issues.apache.org/jira/browse/CB-6452) Incremented plugin version on dev branch. +* [CB-6452](https://issues.apache.org/jira/browse/CB-6452) Updated version and RELEASENOTES.md for release 0.2.9 +* [CB-6460](https://issues.apache.org/jira/browse/CB-6460) Update license headers +* [CB-6422](https://issues.apache.org/jira/browse/CB-6422) [windows8] use cordova/exec/proxy +* [CB-5105](https://issues.apache.org/jira/browse/CB-5105) Removed dead code for device.version +* Add NOTICE file +* [CB-5980](https://issues.apache.org/jira/browse/CB-5980) Incremented plugin version on dev branch. +* Lisa testing pulling in plugins for plugin: cordova-plugin-device +* Lisa testing pulling in plugins for plugin: cordova-plugin-device +* [CB-5980](https://issues.apache.org/jira/browse/CB-5980) Updated version and RELEASENOTES.md for release 0.2.8 +* src/tizen: Adding DeviceProxy. +* plugin.xml: Adding platform tizen. +* supported platforms updated +* Delete stale test/ directory +* Incremented plugin version on dev branch. +* Updated version and RELEASENOTES.md for release 0.2.7 +* [CB-5737](https://issues.apache.org/jira/browse/CB-5737) Fix exception on close caused by left over telephony code from [CB-5504](https://issues.apache.org/jira/browse/CB-5504) +* [CB-5719](https://issues.apache.org/jira/browse/CB-5719) Incremented plugin version on dev branch. +* [CB-5719](https://issues.apache.org/jira/browse/CB-5719) Updated version and RELEASENOTES.md for release 0.2.6 +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Update license comment formatting of doc/index.md +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Add doc.index.md for Device plugin +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Delete stale snapshot of plugin docs +* [CB-5504](https://issues.apache.org/jira/browse/CB-5504) Moving Telephony Logic out of Device +* [CB-5565](https://issues.apache.org/jira/browse/CB-5565) Incremented plugin version on dev branch. +* [CB-5565](https://issues.apache.org/jira/browse/CB-5565) Updated version and RELEASENOTES.md for release 0.2.5 +* [CB-5316](https://issues.apache.org/jira/browse/CB-5316) Spell Cordova as a brand unless it's a command or script +* [ubuntu] use cordova/exec/proxy +* add ubuntu platform +* Modify Device.platform logic to use amazon-fireos as the platform for Amazon Devices +* 1. Added amazon-fireos platform. 2. Change to use cordova-amazon-fireos as the platform if user agent contains 'cordova-amazon-fireos' +* [CB-5188](https://issues.apache.org/jira/browse/CB-5188) +* [CB-5188](https://issues.apache.org/jira/browse/CB-5188) Updated version and RELEASENOTES.md for release 0.2.4 +* [CB-5128](https://issues.apache.org/jira/browse/CB-5128) added repo + issue tag in plugin.xml for device plugin +* [CB-5085](https://issues.apache.org/jira/browse/CB-5085) device.cordova returning wrong value +* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Incremented plugin version on dev branch. +* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Updated version and RELEASENOTES.md for release 0.2.3 +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) bumping&resetting version +* [windows8] commandProxy has moved +* [BlackBerry10] removed uneeded permission tags in plugin.xml +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) renaming org.apache.cordova.core.device to org.apache.cordova.device +* Rename CHANGELOG.md -> RELEASENOTES.md +* updated to use commandProxy for ffos +* add firefoxos support +* [CB-4752](https://issues.apache.org/jira/browse/CB-4752) Incremented plugin version on dev branch. +* [BlackBerry10] removed uneeded permission tags in plugin.xml +* [CB-4752](https://issues.apache.org/jira/browse/CB-4752) Updated version and changelog +* removed extraneous print statement +* [CB-4432](https://issues.apache.org/jira/browse/CB-4432) copyright notice change +* removed extraneous print statement +* [CB-4432](https://issues.apache.org/jira/browse/CB-4432) copyright notice change +* [CB-4595](https://issues.apache.org/jira/browse/CB-4595) updated version +* reverted name element to be user readable +* [CB-4417](https://issues.apache.org/jira/browse/CB-4417) Move cordova-plugin-device to its own Java package. +* updated namespace +* updated readme, namespace and name tag +* [plugin.xml] adding rim namespace +* [plugin.xml] adding android namespace +* [plugin.xml] standardizing license + meta +* [license] adding apache license file +* updating plugin.xml with registry data +* [Windows8] Windows8 is now supported +* added basic Device support for Windows8 + +### 1.1.3 (Sep 08, 2016) +* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to cordovaDependencies +* Add badges for paramedic builds on Jenkins +* Add pull request template. +* Readme: Add fenced code blocks with langauage hints +* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to `README.md` + +### 1.1.2 (Apr 15, 2016) +* Use passed device, follow create policy forf `CFUUIDCreate` +* [CB-10631](https://issues.apache.org/jira/browse/CB-10631) Fix for `device.uuid` in **iOS 5.1.1** +* Updating the comment to exclude URL +* [CB-10636](https://issues.apache.org/jira/browse/CB-10636) Add `JSHint` for plugins +* Refactored `deviceInfo` on **iOS** for better readability. + +### 1.1.1 (Jan 15, 2016) +* [CB-10238](https://issues.apache.org/jira/browse/CB-10238) **OSX** Move `device-plugin` out from `cordovalib` to the plugin repository +* [CB-9923](https://issues.apache.org/jira/browse/CB-9923) Update `device.platform` documentation for **Browser** platform + +### 1.1.0 (Nov 18, 2015) +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated `RELEASENOTES` to be newest to oldest +* Add `isVirtual` for **Windows Phone 8.x** +* Added basic **Android** support for hardware serial number +* [CB-9865](https://issues.apache.org/jira/browse/CB-9865) Better simulator detection for **iOS** +* Fixing contribute link. +* Added **WP8** implementation +* update to use `TARGET_OS_SIMULATOR` as `TARGET_IPHONE_SIMULATOR` is deprecated. +* update code to use 'isVirtual' +* create test to verify existence and type of new property 'isVirtual' +* add `isSimulator` for **iOS** & **Android** device +* Updated documentation to mention backwards compatibility +* Updated **README** to reflect new behaviour and quirks on **iOS** +* Check user defaults first to maintain backwards compatibility +* Changed `UUID` to use `[UIDevice identifierForVendor]` + +### 1.0.1 (Jun 17, 2015) +* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-device documentation translation: cordova-plugin-device +* Attempts to corrent npm markdown issue + +### 1.0.0 (Apr 15, 2015) +* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) gave plugin major version bump +* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) changed plugin-id to pacakge-name +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) properly updated translated docs to use new id +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id +* Use TRAVIS_BUILD_DIR, install paramedic by npm +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) Updated Readme +* remove defunct windows8 version +* add travis badge +* Add cross-plugin ios paramedic test running for TravisCI +* [CB-8538](https://issues.apache.org/jira/browse/CB-8538) Added package.json file + +### 0.3.0 (Feb 04, 2015) +* Added device.manufacturer property for Android, iOS, Blackberry, WP8 +* Support for Windows Phone 8 ANID2 ANID is only supported up to Windows Phone 7.5 +* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) Use a local copy of uniqueAppInstanceIdentifier rather than CordovaLib's version +* browser: Fixed a bug that caused an "cannot call method of undefined" error if the browser's user agent wasn't recognized + +### 0.2.13 (Dec 02, 2014) +* Changing `device.platform` to always report the platform as "browser". +* [CB-5892](https://issues.apache.org/jira/browse/CB-5892) - Remove deprecated `window.Settings` +* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-device documentation translation: cordova-plugin-device +* [CB-7571](https://issues.apache.org/jira/browse/CB-7571) Bump version of nested plugin to match parent plugin + +### 0.2.12 (Sep 17, 2014) +* [CB-7471](https://issues.apache.org/jira/browse/CB-7471) cordova-plugin-device documentation translation +* [CB-7552](https://issues.apache.org/jira/browse/CB-7552) device.name docs have not been removed +* [fxos] Fix cordova version +* added status box and documentation to manual tests +* [fxos] Fix cordova version +* added status box and documentation to manual tests +* Added plugin support for the browser +* [CB-7262](https://issues.apache.org/jira/browse/CB-7262) Adds support for universal windows apps. + +### 0.2.11 (Aug 06, 2014) +* [FFOS] update DeviceProxy.js +* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Updated translations for docs +* Use Windows system calls to get better info + +### 0.2.10 (Jun 05, 2014) +* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Spanish and French Translations added. Github close #12 +* Changing 1.5 to 2.0 +* added firefoxos version - conversion +* added firefoxos version +* [CB-6800](https://issues.apache.org/jira/browse/CB-6800) Add license +* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md + +### 0.2.9 (Apr 17, 2014) +* [CB-5105](https://issues.apache.org/jira/browse/CB-5105): [Android, windows8, WP, BlackBerry10] Removed dead code for device.version +* [CB-6422](https://issues.apache.org/jira/browse/CB-6422): [windows8] use cordova/exec/proxy +* [CB-6460](https://issues.apache.org/jira/browse/CB-6460): Update license headers +* Add NOTICE file + +### 0.2.8 (Feb 05, 2014) +* Tizen support added + +### 0.2.7 (Jan 07, 2014) +* [CB-5737](https://issues.apache.org/jira/browse/CB-5737) Fix exception on close caused by left over telephony code from [CB-5504](https://issues.apache.org/jira/browse/CB-5504) + +### 0.2.6 (Jan 02, 2014) +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Add doc/index.md for Device plugin +* [CB-5504](https://issues.apache.org/jira/browse/CB-5504) Moving Telephony Logic out of Device + +### 0.2.5 (Dec 4, 2013) +* [CB-5316](https://issues.apache.org/jira/browse/CB-5316) Spell Cordova as a brand unless it's a command or script +* [ubuntu] use cordova/exec/proxy +* add ubuntu platform +* Modify Device.platform logic to use amazon-fireos as the platform for Amazon Devices +* 1. Added amazon-fireos platform. 2. Change to use cordova-amazon-fireos as the platform if user agent contains 'cordova-amazon-fireos' + +### 0.2.4 (Oct 28, 2013) +* [CB-5128](https://issues.apache.org/jira/browse/CB-5128): added repo + issue tag in plugin.xml for device plugin +* [CB-5085](https://issues.apache.org/jira/browse/CB-5085) device.cordova returning wrong value +* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Incremented plugin version on dev branch. + +### 0.2.3 (Sept 25, 2013) +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) bumping&resetting version +* [windows8] commandProxy has moved +* [BlackBerry10] removed uneeded permission tags in plugin.xml +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) renaming org.apache.cordova.core.device to org.apache.cordova.device +* Rename CHANGELOG.md -> RELEASENOTES.md +* updated to use commandProxy for ffos +* add firefoxos support +* [CB-4752](https://issues.apache.org/jira/browse/CB-4752) Incremented plugin version on dev branch. + +### 0.2.1 (Sept 5, 2013) +* removed extraneous print statement +* [CB-4432](https://issues.apache.org/jira/browse/CB-4432) copyright notice change diff --git a/mobile/plugins/cordova-plugin-device/doc/de/README.md b/mobile/plugins/cordova-plugin-device/doc/de/README.md new file mode 100644 index 0000000..81f89e9 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/de/README.md @@ -0,0 +1,203 @@ + + +# cordova-plugin-device + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device) + +Dieses Plugin definiert eine globale `device` -Objekt, das des Geräts Hard- und Software beschreibt. Das Objekt im globalen Gültigkeitsbereich ist es zwar nicht verfügbar bis nach dem `deviceready` Ereignis. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Installation + + cordova plugin add cordova-plugin-device + + +## Eigenschaften + + * device.cordova + * device.model + * device.platform + * device.uuid + * device.version + +## device.cordova + +Rufen Sie die Version von Cordova, die auf dem Gerät ausgeführt. + +### Unterstützte Plattformen + + * Amazon Fire OS + * Android + * BlackBerry 10 + * Browser + * Firefox OS + * iOS + * Tizen + * Windows Phone 7 und 8 + * Windows 8 + +## device.model + +Die `device.model` gibt den Namen der Modell- oder des Geräts zurück. Der Wert wird vom Gerätehersteller festgelegt und kann zwischen den Versionen des gleichen Produkts unterschiedlich sein. + +### Unterstützte Plattformen + + * Android + * BlackBerry 10 + * Browser + * iOS + * Tizen + * Windows Phone 7 und 8 + * Windows 8 + +### Kurzes Beispiel + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Finden Sie unter http://theiphonewiki.com/wiki/index.php?title=Models / / Var-Modell = device.model; + + +### Android Eigenarten + + * Ruft den [Produktname](http://developer.android.com/reference/android/os/Build.html#PRODUCT) anstelle des [Modellnamens](http://developer.android.com/reference/android/os/Build.html#MODEL), das ist oft der Codename für die Produktion. Beispielsweise das Nexus One gibt `Passion` , und Motorola Droid gibt`voles`. + +### Tizen Macken + + * Gibt z. B. das Gerätemodell von dem Kreditor zugeordnet,`TIZEN` + +### Windows Phone 7 und 8 Eigenarten + + * Gibt das vom Hersteller angegebenen Gerätemodell zurück. Beispielsweise gibt der Samsung-Fokus`SGH-i917`. + +## device.platform + +Name des Betriebssystems des Geräts zu erhalten. + + var string = device.platform; + + +### Unterstützte Plattformen + + * Android + * BlackBerry 10 + * Browser4 + * Firefox OS + * iOS + * Tizen + * Windows Phone 7 und 8 + * Windows 8 + +### Kurzes Beispiel + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 Macken + +Windows Phone 7 Geräte melden die Plattform als`WinCE`. + +### Windows Phone 8 Macken + +Windows Phone 8 Geräte melden die Plattform als`Win32NT`. + +## device.uuid + +Des Geräts Universally Unique Identifier ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier) zu erhalten). + + var string = device.uuid; + + +### Beschreibung + +Die Details wie eine UUID generiert wird werden vom Gerätehersteller und beziehen sich auf die Plattform oder das Modell des Geräts. + +### Unterstützte Plattformen + + * Android + * BlackBerry 10 + * iOS + * Tizen + * Windows Phone 7 und 8 + * Windows 8 + +### Kurzes Beispiel + + / / Android: wird eine zufällige 64-Bit-Ganzzahl (als Zeichenfolge, wieder!) / / die ganze Zahl wird beim ersten Start des Geräts erzeugt / / / / BlackBerry: gibt die PIN-Nummer des Gerätes / / Dies ist eine neunstellige eindeutige Ganzzahl (als String, obwohl!) / / / / iPhone: (paraphrasiert aus der Dokumentation zur UIDevice-Klasse) / / liefert eine Reihe von Hash-Werte, die aus mehreren Hardware erstellt identifiziert. + / / Es ist gewährleistet, dass für jedes Gerät eindeutig sein und kann nicht gebunden werden / / an den Benutzer weitergeleitet. + / / Windows Phone 7: gibt einen Hash des Gerät + aktueller Benutzer, / / wenn der Benutzer nicht definiert ist, eine Guid generiert und wird weiter bestehen, bis die app deinstalliert wird / / Tizen: gibt das Gerät IMEI (International Mobile Equipment Identity oder IMEI ist eine Zahl / / einzigartig für jedes GSM- und UMTS-Handy. + var deviceID = device.uuid; + + +### iOS Quirk + +Die `uuid` auf iOS ist nicht eindeutig zu einem Gerät, aber für jede Anwendung, für jede Installation variiert. Es ändert sich, wenn Sie löschen und neu die app installieren, und möglicherweise auch beim iOS zu aktualisieren, oder auch ein Upgrade möglich die app pro Version (scheinbaren in iOS 5.1). Die `uuid` ist kein zuverlässiger Wert. + +### Windows Phone 7 und 8 Eigenarten + +Die `uuid` für Windows Phone 7 die Berechtigung erfordert `ID_CAP_IDENTITY_DEVICE` . Microsoft wird diese Eigenschaft wahrscheinlich bald abzuschaffen. Wenn die Funktion nicht verfügbar ist, generiert die Anwendung eine persistente Guid, die für die Dauer der Installation der Anwendung auf dem Gerät gewährleistet ist. + +## device.version + +Version des Betriebssystems zu erhalten. + + var string = device.version; + + +### Unterstützte Plattformen + + * Android 2.1 + + * BlackBerry 10 + * Browser + * iOS + * Tizen + * Windows Phone 7 und 8 + * Windows 8 + +### Kurzes Beispiel + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/doc/de/index.md b/mobile/plugins/cordova-plugin-device/doc/de/index.md new file mode 100644 index 0000000..e3a537e --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/de/index.md @@ -0,0 +1,206 @@ + + +# cordova-plugin-device + +Dieses Plugin definiert eine globale `device` -Objekt, das des Geräts Hard- und Software beschreibt. Das Objekt im globalen Gültigkeitsbereich ist es zwar nicht verfügbar bis nach dem `deviceready` Ereignis. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Installation + + cordova plugin add cordova-plugin-device + + +## Eigenschaften + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +Rufen Sie die Version von Cordova, die auf dem Gerät ausgeführt. + +### Unterstützte Plattformen + +* Amazon Fire OS +* Android +* BlackBerry 10 +* Browser +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 und 8 +* Windows 8 + +## device.model + +Die `device.model` gibt den Namen der Modell- oder des Geräts zurück. Der Wert wird vom Gerätehersteller festgelegt und kann zwischen den Versionen des gleichen Produkts unterschiedlich sein. + +### Unterstützte Plattformen + +* Android +* BlackBerry 10 +* Browser +* iOS +* Tizen +* Windows Phone 7 und 8 +* Windows 8 + +### Kurzes Beispiel + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Finden Sie unter http://theiphonewiki.com/wiki/index.php?title=Models / / Var-Modell = device.model; + + +### Android Eigenarten + +* Ruft den [Produktname][1] anstelle des [Modellnamens][2], das ist oft der Codename für die Produktion. Beispielsweise das Nexus One gibt `Passion` , und Motorola Droid gibt`voles`. + + [1]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + [2]: http://developer.android.com/reference/android/os/Build.html#MODEL + +### Tizen Macken + +* Gibt z. B. das Gerätemodell von dem Kreditor zugeordnet,`TIZEN` + +### Windows Phone 7 und 8 Eigenarten + +* Gibt das vom Hersteller angegebenen Gerätemodell zurück. Beispielsweise gibt der Samsung-Fokus`SGH-i917`. + +## device.platform + +Name des Betriebssystems des Geräts zu erhalten. + + var string = device.platform; + + +### Unterstützte Plattformen + +* Android +* BlackBerry 10 +* Browser4 +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 und 8 +* Windows 8 + +### Kurzes Beispiel + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 Macken + +Windows Phone 7 Geräte melden die Plattform als`WinCE`. + +### Windows Phone 8 Macken + +Windows Phone 8 Geräte melden die Plattform als`Win32NT`. + +## device.uuid + +Des Geräts Universally Unique Identifier ([UUID][3] zu erhalten). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### Beschreibung + +Die Details wie eine UUID generiert wird werden vom Gerätehersteller und beziehen sich auf die Plattform oder das Modell des Geräts. + +### Unterstützte Plattformen + +* Android +* BlackBerry 10 +* iOS +* Tizen +* Windows Phone 7 und 8 +* Windows 8 + +### Kurzes Beispiel + + / / Android: wird eine zufällige 64-Bit-Ganzzahl (als Zeichenfolge, wieder!) / / die ganze Zahl wird beim ersten Start des Geräts erzeugt / / / / BlackBerry: gibt die PIN-Nummer des Gerätes / / Dies ist eine neunstellige eindeutige Ganzzahl (als String, obwohl!) / / / / iPhone: (paraphrasiert aus der Dokumentation zur UIDevice-Klasse) / / liefert eine Reihe von Hash-Werte, die aus mehreren Hardware erstellt identifiziert. + / / Es ist gewährleistet, dass für jedes Gerät eindeutig sein und kann nicht gebunden werden / / an den Benutzer weitergeleitet. + / / Windows Phone 7: gibt einen Hash des Gerät + aktueller Benutzer, / / wenn der Benutzer nicht definiert ist, eine Guid generiert und wird weiter bestehen, bis die app deinstalliert wird / / Tizen: gibt das Gerät IMEI (International Mobile Equipment Identity oder IMEI ist eine Zahl / / einzigartig für jedes GSM- und UMTS-Handy. + var deviceID = device.uuid; + + +### iOS Quirk + +Die `uuid` auf iOS ist nicht eindeutig zu einem Gerät, aber für jede Anwendung, für jede Installation variiert. Es ändert sich, wenn Sie löschen und neu die app installieren, und möglicherweise auch beim iOS zu aktualisieren, oder auch ein Upgrade möglich die app pro Version (scheinbaren in iOS 5.1). Die `uuid` ist kein zuverlässiger Wert. + +### Windows Phone 7 und 8 Eigenarten + +Die `uuid` für Windows Phone 7 die Berechtigung erfordert `ID_CAP_IDENTITY_DEVICE` . Microsoft wird diese Eigenschaft wahrscheinlich bald abzuschaffen. Wenn die Funktion nicht verfügbar ist, generiert die Anwendung eine persistente Guid, die für die Dauer der Installation der Anwendung auf dem Gerät gewährleistet ist. + +## device.version + +Version des Betriebssystems zu erhalten. + + var string = device.version; + + +### Unterstützte Plattformen + +* Android 2.1 + +* BlackBerry 10 +* Browser +* iOS +* Tizen +* Windows Phone 7 und 8 +* Windows 8 + +### Kurzes Beispiel + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/doc/es/README.md b/mobile/plugins/cordova-plugin-device/doc/es/README.md new file mode 100644 index 0000000..a27abfb --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/es/README.md @@ -0,0 +1,216 @@ + + +# cordova-plugin-device + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device) + +Este plugin define un global `device` objeto que describe del dispositivo hardware y software. Aunque el objeto está en el ámbito global, no está disponible hasta después de la `deviceready` evento. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Instalación + + cordova plugin add cordova-plugin-device + + +## Propiedades + + * device.cordova + * device.model + * device.platform + * device.uuid + * device.version + +## device.cordova + +Obtener la versión de Cordova que se ejecuta en el dispositivo. + +### Plataformas soportadas + + * Amazon fire OS + * Android + * BlackBerry 10 + * Explorador + * Firefox OS + * iOS + * Tizen + * Windows Phone 7 y 8 + * Windows 8 + +## device.model + +El `device.model` devuelve el nombre de modelo del dispositivo o producto. El valor es fijado por el fabricante del dispositivo y puede ser diferente a través de versiones del mismo producto. + +### Plataformas soportadas + + * Android + * BlackBerry 10 + * Explorador + * iOS + * Tizen + * Windows Phone 7 y 8 + * Windows 8 + +### Ejemplo rápido + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. See http://theiphonewiki.com/wiki/index.php?title=Models + // + var model = device.model; + + +### Rarezas Android + + * Obtiene el [nombre del producto](http://developer.android.com/reference/android/os/Build.html#PRODUCT) en lugar del [nombre de la modelo](http://developer.android.com/reference/android/os/Build.html#MODEL), que es a menudo el nombre de código de producción. Por ejemplo, el Nexus One devuelve `Passion` y Motorola Droid devuelve `voles`. + +### Rarezas Tizen + + * Devuelve que el modelo de dispositivo asignado por el proveedor, por ejemplo, `TIZEN` + +### Windows Phone 7 y 8 rarezas + + * Devuelve el modelo de dispositivo especificado por el fabricante. Por ejemplo, el Samsung Focus devuelve `SGH-i917`. + +## device.platform + +Obtener el nombre del sistema operativo del dispositivo. + + var string = device.platform; + + +### Plataformas soportadas + + * Android + * BlackBerry 10 + * Browser4 + * Firefox OS + * iOS + * Tizen + * Windows Phone 7 y 8 + * Windows 8 + +### Ejemplo rápido + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 rarezas + +Dispositivos Windows Phone 7 informe de la plataforma como `WinCE`. + +### Windows Phone 8 rarezas + +Dispositivos Windows Phone 8 Informe la plataforma como `Win32NT`. + +## device.uuid + +Obtener identificador universalmente única del dispositivo ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier)). + + var string = device.uuid; + + +### Descripción + +Los detalles de cómo se genera un UUID son determinados por el fabricante del dispositivo y son específicos a la plataforma del dispositivo o modelo. + +### Plataformas soportadas + + * Android + * BlackBerry 10 + * iOS + * Tizen + * Windows Phone 7 y 8 + * Windows 8 + +### Ejemplo rápido + + // Android: Returns a random 64-bit integer (as a string, again!) + // The integer is generated on the device's first boot + // + // BlackBerry: Returns the PIN number of the device + // This is a nine-digit unique integer (as a string, though!) + // + // iPhone: (Paraphrased from the UIDevice Class documentation) + // Returns a string of hash values created from multiple hardware identifies. + // It is guaranteed to be unique for every device and can't be tied + // to the user account. + // Windows Phone 7 : Returns a hash of device+current user, + // if the user is not defined, a guid is generated and will persist until the app is uninstalled + // Tizen: returns the device IMEI (International Mobile Equipment Identity or IMEI is a number + // unique to every GSM and UMTS mobile phone. + var deviceID = device.uuid; + + +### Rarezas de iOS + +El `uuid` en iOS no es exclusiva de un dispositivo, pero varía para cada aplicación, para cada instalación. Cambia si puedes borrar y volver a instalar la aplicación, y posiblemente también cuándo actualizar iOS, o incluso mejorar la aplicación por la versión (evidente en iOS 5.1). El `uuid` no es un valor confiable. + +### Windows Phone 7 y 8 rarezas + +El `uuid` para Windows Phone 7 requiere el permiso `ID_CAP_IDENTITY_DEVICE`. Microsoft pronto probablemente desaprueban esta propiedad. Si la capacidad no está disponible, la aplicación genera un guid persistente que se mantiene durante la duración de la instalación de la aplicación en el dispositivo. + +## device.version + +Obtener la versión del sistema operativo. + + var string = device.version; + + +### Plataformas soportadas + + * Android 2.1 + + * BlackBerry 10 + * Explorador + * iOS + * Tizen + * Windows Phone 7 y 8 + * Windows 8 + +### Ejemplo rápido + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/doc/es/index.md b/mobile/plugins/cordova-plugin-device/doc/es/index.md new file mode 100644 index 0000000..f4a5897 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/es/index.md @@ -0,0 +1,220 @@ + + +# cordova-plugin-device + +Este plugin define un global `device` objeto que describe del dispositivo hardware y software. Aunque el objeto está en el ámbito global, no está disponible hasta después de la `deviceready` evento. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Instalación + + cordova plugin add cordova-plugin-device + + +## Propiedades + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +Obtener la versión de Cordova que se ejecuta en el dispositivo. + +### Plataformas soportadas + +* Amazon fire OS +* Android +* BlackBerry 10 +* Explorador +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 y 8 +* Windows 8 + +## device.model + +El `device.model` devuelve el nombre de modelo del dispositivo o producto. El valor es fijado por el fabricante del dispositivo y puede ser diferente a través de versiones del mismo producto. + +### Plataformas soportadas + +* Android +* BlackBerry 10 +* Explorador +* iOS +* Tizen +* Windows Phone 7 y 8 +* Windows 8 + +### Ejemplo rápido + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. See http://theiphonewiki.com/wiki/index.php?title=Models + // + var model = device.model; + + +### Rarezas Android + +* Obtiene el [nombre del producto][1] en lugar del [nombre de la modelo][2], que es a menudo el nombre de código de producción. Por ejemplo, el Nexus One devuelve `Passion` y Motorola Droid devuelve `voles`. + + [1]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + [2]: http://developer.android.com/reference/android/os/Build.html#MODEL + +### Rarezas Tizen + +* Devuelve que el modelo de dispositivo asignado por el proveedor, por ejemplo, `TIZEN` + +### Windows Phone 7 y 8 rarezas + +* Devuelve el modelo de dispositivo especificado por el fabricante. Por ejemplo, el Samsung Focus devuelve `SGH-i917`. + +## device.platform + +Obtener el nombre del sistema operativo del dispositivo. + + var string = device.platform; + + +### Plataformas soportadas + +* Android +* BlackBerry 10 +* Browser4 +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 y 8 +* Windows 8 + +### Ejemplo rápido + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 rarezas + +Dispositivos Windows Phone 7 informe de la plataforma como `WinCE`. + +### Windows Phone 8 rarezas + +Dispositivos Windows Phone 8 Informe la plataforma como `Win32NT`. + +## device.uuid + +Obtener identificador universalmente única del dispositivo ([UUID][3]). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### Descripción + +Los detalles de cómo se genera un UUID son determinados por el fabricante del dispositivo y son específicos a la plataforma del dispositivo o modelo. + +### Plataformas soportadas + +* Android +* BlackBerry 10 +* iOS +* Tizen +* Windows Phone 7 y 8 +* Windows 8 + +### Ejemplo rápido + + // Android: devuelve un entero de 64 bits al azar (como una cadena, otra vez!) + // el entero es generado en el primer arranque del dispositivo + // + // BlackBerry: devuelve el número PIN del dispositivo + // este es un entero único de nueve dígitos (como una cadena, aunque!) + // + // iPhone: (parafraseado de la documentación de la clase UIDevice) + // devuelve una cadena de valores hash creado a partir + // de múltiples hardware identifica. + / / Está garantizado para ser único para cada dispositivo y no puede ser atado / / a la cuenta de usuario. + // Windows Phone 7: devuelve un hash de dispositivo + usuario actual, + // si el usuario no está definido, un guid generado y persistirá hasta que se desinstala la aplicación + // + // Tizen: devuelve el dispositivo IMEI (identidad de equipo móvil internacional o IMEI es un número + // único para cada teléfono móvil GSM y UMTS. + var deviceID = device.uuid; + + +### iOS chanfle + +El `uuid` en iOS no es exclusiva de un dispositivo, pero varía para cada aplicación, para cada instalación. Cambia si puedes borrar y volver a instalar la aplicación, y posiblemente también cuándo actualizar iOS, o incluso mejorar la aplicación por la versión (evidente en iOS 5.1). El `uuid` no es un valor confiable. + +### Windows Phone 7 y 8 rarezas + +El `uuid` para Windows Phone 7 requiere el permiso `ID_CAP_IDENTITY_DEVICE`. Microsoft pronto probablemente desaprueban esta propiedad. Si la capacidad no está disponible, la aplicación genera un guid persistente que se mantiene durante la duración de la instalación de la aplicación en el dispositivo. + +## device.version + +Obtener la versión del sistema operativo. + + var string = device.version; + + +### Plataformas soportadas + +* Android 2.1 + +* BlackBerry 10 +* Explorador +* iOS +* Tizen +* Windows Phone 7 y 8 +* Windows 8 + +### Ejemplo rápido + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. el Mango se vuelve 7.10.7720 + // Tizen: devuelve "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/doc/fr/README.md b/mobile/plugins/cordova-plugin-device/doc/fr/README.md new file mode 100644 index 0000000..4101fd9 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/fr/README.md @@ -0,0 +1,215 @@ + + +# cordova-plugin-device + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device) + +Ce plugin définit un global `device` objet qui décrit le matériel et les logiciels de l'appareil. Bien que l'objet est dans la portée globale, il n'est pas disponible jusqu'après la `deviceready` événement. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Installation + + cordova plugin add cordova-plugin-device + + +## Propriétés + + * device.cordova + * device.model + * device.platform + * device.uuid + * device.version + +## device.cordova + +Retourne la version de Cordova en cours d'exécution sur l'appareil. + +### Plates-formes supportées + + * Amazon Fire OS + * Android + * BlackBerry 10 + * Navigateur + * Firefox OS + * iOS + * Paciarelli + * Windows Phone 7 et 8 + * Windows 8 + +## device.model + +L'objet `device.model` retourne le nom du modèle de l'appareil/produit. Cette valeur est définie par le fabricant du périphérique et peut varier entre les différentes versions d'un même produit. + +### Plates-formes supportées + + * Android + * BlackBerry 10 + * Navigateur + * iOS + * Paciarelli + * Windows Phone 7 et 8 + * Windows 8 + +### Exemple court + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Voir http://theiphonewiki.com/wiki/index.php?title=Models + // + var model = device.model; + + +### Quirks Android + + * Retourne le [nom du produit](http://developer.android.com/reference/android/os/Build.html#PRODUCT) au lieu du [nom du modèle](http://developer.android.com/reference/android/os/Build.html#MODEL), ce qui équivaut souvent au nom de code de production. Par exemple, `Passion` pour le Nexus One et `voles` pour le Motorola Droid. + +### Bizarreries de paciarelli + + * Retourne le modèle du dispositif, assigné par le vendeur, par exemple `TIZEN` + +### Notes au sujet de Windows Phone 7 et 8 + + * Retourne le modèle de l'appareil spécifié par le fabricant. Par exemple `SGH-i917` pour le Samsung Focus. + +## device.platform + +Obtenir le nom de système d'exploitation de l'appareil. + + var string = device.platform; + + +### Plates-formes supportées + + * Android + * BlackBerry 10 + * Browser4 + * Firefox OS + * iOS + * Paciarelli + * Windows Phone 7 et 8 + * Windows 8 + +### Exemple court + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 Quirks + +Appareils Windows Phone 7 rapport de la plate-forme comme`WinCE`. + +### Notes au sujet de Windows Phone 8 + +Appareils Windows Phone 8 rapport de la plate-forme comme`Win32NT`. + +## device.uuid + +Obtenir Universally Unique Identifier de l'appareil ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier)). + + var string = device.uuid; + + +### Description + +Les détails de comment un UUID généré sont déterminées par le fabricant du périphérique et sont spécifiques à la plate-forme ou le modèle de l'appareil. + +### Plates-formes supportées + + * Android + * BlackBerry 10 + * iOS + * Paciarelli + * Windows Phone 7 et 8 + * Windows 8 + +### Exemple court + + // Android : retourne un nombre entier 64-bit aléatoire (sous la forme d'une chaîne de caractères, encore !) + // Ce nombre entier est généré lors du premier démarrage de l'appareil + // + // BlackBerry : retourne le numéro PIN de l'appareil + // Il s'agit d'un nombre entier unique à neuf chiffres (sous la forme d'une chaîne de caractères cependant !) + // + // iPhone : (copié depuis la documentation de la classe UIDevice) + // Retourne une chaîne de caractères générée à partir de plusieurs caractéristiques matérielles. + / / Il est garanti pour être unique pour chaque appareil et ne peut pas être lié / / pour le compte d'utilisateur. + // Windows Phone 7 : retourne un hashage généré à partir de appareil+utilisateur actuel, + // si aucun utilisateur n'est défini, un guid est généré persistera jusqu'à ce que l'application soit désinstallée + // Tizen : retourne le numéro IMEI (International Mobile Equipment Identity) de l'appareil, ce numéro est + // unique pour chaque téléphone GSM et UMTS. + var deviceID = device.uuid; + + +### Spécificités iOS + +Le `uuid` sur iOS n'est pas propre à un périphérique, mais varie pour chaque application, pour chaque installation. Elle change si vous supprimez, puis réinstallez l'application, et éventuellement aussi quand vous mettre à jour d'iOS, ou même mettre à jour le soft par version (apparent dans iOS 5.1). Le `uuid` n'est pas une valeur fiable. + +### Notes au sujet de Windows Phone 7 et 8 + +Le `uuid` pour Windows Phone 7 requiert l'autorisation `ID_CAP_IDENTITY_DEVICE` . Microsoft va probablement bientôt obsolète de cette propriété. Si la capacité n'est pas disponible, l'application génère un guid persistant qui est maintenu pendant toute la durée de l'installation de l'application sur le périphérique. + +## device.version + +Téléchargez la version de système d'exploitation. + + var string = device.version; + + +### Plates-formes supportées + + * Android 2.1+ + * BlackBerry 10 + * Navigateur + * iOS + * Paciarelli + * Windows Phone 7 et 8 + * Windows 8 + +### Exemple court + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/doc/fr/index.md b/mobile/plugins/cordova-plugin-device/doc/fr/index.md new file mode 100644 index 0000000..163e498 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/fr/index.md @@ -0,0 +1,218 @@ + + +# cordova-plugin-device + +Ce plugin définit un global `device` objet qui décrit le matériel et les logiciels de l'appareil. Bien que l'objet est dans la portée globale, il n'est pas disponible jusqu'après la `deviceready` événement. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Installation + + cordova plugin add cordova-plugin-device + + +## Propriétés + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +Retourne la version de Cordova en cours d'exécution sur l'appareil. + +### Plates-formes prises en charge + +* Amazon Fire OS +* Android +* BlackBerry 10 +* Navigateur +* Firefox OS +* iOS +* Paciarelli +* Windows Phone 7 et 8 +* Windows 8 + +## device.model + +L'objet `device.model` retourne le nom du modèle de l'appareil/produit. Cette valeur est définie par le fabricant du périphérique et peut varier entre les différentes versions d'un même produit. + +### Plates-formes prises en charge + +* Android +* BlackBerry 10 +* Navigateur +* iOS +* Paciarelli +* Windows Phone 7 et 8 +* Windows 8 + +### Petit exemple + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Voir http://theiphonewiki.com/wiki/index.php?title=Models + // + var model = device.model; + + +### Quirks Android + +* Retourne le [nom du produit][1] au lieu du [nom du modèle][2], ce qui équivaut souvent au nom de code de production. Par exemple, `Passion` pour le Nexus One et `voles` pour le Motorola Droid. + + [1]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + [2]: http://developer.android.com/reference/android/os/Build.html#MODEL + +### Bizarreries de paciarelli + +* Retourne le modèle du dispositif, assigné par le vendeur, par exemple `TIZEN` + +### Windows Phone 7 et 8 Quirks + +* Retourne le modèle de l'appareil spécifié par le fabricant. Par exemple `SGH-i917` pour le Samsung Focus. + +## device.platform + +Obtenir le nom de système d'exploitation de l'appareil. + + var string = device.platform; + + +### Plates-formes prises en charge + +* Android +* BlackBerry 10 +* Browser4 +* Firefox OS +* iOS +* Paciarelli +* Windows Phone 7 et 8 +* Windows 8 + +### Petit exemple + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 Quirks + +Appareils Windows Phone 7 rapport de la plate-forme comme`WinCE`. + +### Notes au sujet de Windows Phone 8 + +Appareils Windows Phone 8 rapport de la plate-forme comme`Win32NT`. + +## device.uuid + +Obtenir Universally Unique Identifier de l'appareil ([UUID][3]). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### Description + +Les détails de comment un UUID généré sont déterminées par le fabricant du périphérique et sont spécifiques à la plate-forme ou le modèle de l'appareil. + +### Plates-formes prises en charge + +* Android +* BlackBerry 10 +* iOS +* Paciarelli +* Windows Phone 7 et 8 +* Windows 8 + +### Petit exemple + + // Android : retourne un nombre entier 64-bit aléatoire (sous la forme d'une chaîne de caractères, encore !) + // Ce nombre entier est généré lors du premier démarrage de l'appareil + // + // BlackBerry : retourne le numéro PIN de l'appareil + // Il s'agit d'un nombre entier unique à neuf chiffres (sous la forme d'une chaîne de caractères cependant !) + // + // iPhone : (copié depuis la documentation de la classe UIDevice) + // Retourne une chaîne de caractères générée à partir de plusieurs caractéristiques matérielles. + / / Il est garanti pour être unique pour chaque appareil et ne peut pas être lié / / pour le compte d'utilisateur. + // Windows Phone 7 : retourne un hashage généré à partir de appareil+utilisateur actuel, + // si aucun utilisateur n'est défini, un guid est généré persistera jusqu'à ce que l'application soit désinstallée + // Tizen : retourne le numéro IMEI (International Mobile Equipment Identity) de l'appareil, ce numéro est + // unique pour chaque téléphone GSM et UMTS. + var deviceID = device.uuid; + + +### Spécificités iOS + +Le `uuid` sur iOS n'est pas propre à un périphérique, mais varie pour chaque application, pour chaque installation. Elle change si vous supprimez, puis réinstallez l'application, et éventuellement aussi quand vous mettre à jour d'iOS, ou même mettre à jour le soft par version (apparent dans iOS 5.1). Le `uuid` n'est pas une valeur fiable. + +### Windows Phone 7 et 8 Quirks + +Le `uuid` pour Windows Phone 7 requiert l'autorisation `ID_CAP_IDENTITY_DEVICE` . Microsoft va probablement bientôt obsolète de cette propriété. Si la capacité n'est pas disponible, l'application génère un guid persistant qui est maintenu pendant toute la durée de l'installation de l'application sur le périphérique. + +## device.version + +Téléchargez la version de système d'exploitation. + + var string = device.version; + + +### Plates-formes prises en charge + +* Android 2.1+ +* BlackBerry 10 +* Navigateur +* iOS +* Paciarelli +* Windows Phone 7 et 8 +* Windows 8 + +### Petit exemple + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/doc/it/README.md b/mobile/plugins/cordova-plugin-device/doc/it/README.md new file mode 100644 index 0000000..7974962 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/it/README.md @@ -0,0 +1,203 @@ + + +# cordova-plugin-device + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device) + +Questo plugin definisce un global `device` oggetto che descrive il dispositivo hardware e software. Sebbene l'oggetto sia in ambito globale, non è disponibile fino a dopo il `deviceready` evento. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Installazione + + cordova plugin add cordova-plugin-device + + +## Proprietà + + * device.cordova + * device.model + * device.platform + * device.uuid + * device.version + +## device.cordova + +Ottenere la versione di Cordova in esecuzione nel dispositivo. + +### Piattaforme supportate + + * Amazon fuoco OS + * Android + * BlackBerry 10 + * Browser + * Firefox OS + * iOS + * Tizen + * Windows Phone 7 e 8 + * Windows 8 + +## device.model + +Il `device.model` restituisce il nome del modello del dispositivo o del prodotto. Il valore viene impostato dal produttore del dispositivo e può essere differente tra le versioni dello stesso prodotto. + +### Piattaforme supportate + + * Android + * BlackBerry 10 + * Browser + * iOS + * Tizen + * Windows Phone 7 e 8 + * Windows 8 + +### Esempio rapido + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Vedi http://theiphonewiki.com/wiki/index.php?title=Models / / modello var = device.model; + + +### Stranezze Android + + * Ottiene il [nome del prodotto](http://developer.android.com/reference/android/os/Build.html#PRODUCT) anziché il [nome del modello](http://developer.android.com/reference/android/os/Build.html#MODEL), che è spesso il nome di codice di produzione. Ad esempio, restituisce il Nexus One `Passion` , e Motorola Droid restituisce`voles`. + +### Tizen stranezze + + * Restituisce il modello di dispositivo assegnato dal fornitore, ad esempio,`TIZEN` + +### Windows Phone 7 e 8 stranezze + + * Restituisce il modello di dispositivo specificato dal produttore. Ad esempio, restituisce il Samsung Focus`SGH-i917`. + +## device.platform + +Ottenere il nome del sistema operativo del dispositivo. + + var string = device.platform; + + +### Piattaforme supportate + + * Android + * BlackBerry 10 + * Browser4 + * Firefox OS + * iOS + * Tizen + * Windows Phone 7 e 8 + * Windows 8 + +### Esempio rapido + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 capricci + +Windows Phone 7 dispositivi segnalano la piattaforma come`WinCE`. + +### Windows Phone 8 stranezze + +Dispositivi Windows Phone 8 segnalano la piattaforma come`Win32NT`. + +## device.uuid + +Ottenere identificatore del dispositivo univoco universale ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier)). + + var string = device.uuid; + + +### Descrizione + +I dettagli di come viene generato un UUID sono determinati dal produttore del dispositivo e sono specifici per la piattaforma o il modello del dispositivo. + +### Piattaforme supportate + + * Android + * BlackBerry 10 + * iOS + * Tizen + * Windows Phone 7 e 8 + * Windows 8 + +### Esempio rapido + + / / Android: restituisce un intero casuale di 64 bit (come stringa, ancora una volta!) / / il numero intero è generato al primo avvio del dispositivo / / / / BlackBerry: restituisce il numero PIN del dispositivo / / questo è un valore integer univoco a nove cifre (come stringa, benchè!) / / / / iPhone: (parafrasato dalla documentazione della classe UIDevice) / / restituisce una stringa di valori hash creata dall'hardware più identifica. + / / È garantito per essere unica per ogni dispositivo e non può essere legato / / per l'account utente. + / / Windows Phone 7: restituisce un hash dell'utente corrente, + dispositivo / / se l'utente non è definito, un guid generato e persisterà fino a quando l'applicazione viene disinstallata / / Tizen: restituisce il dispositivo IMEI (International Mobile Equipment Identity o IMEI è un numero / / unico per ogni cellulare GSM e UMTS. + var deviceID = device.uuid; + + +### iOS Quirk + +Il `uuid` su iOS non è univoco per un dispositivo, ma varia per ogni applicazione, per ogni installazione. Cambia se si elimina e re-installare l'app, e possibilmente anche quando aggiornare iOS o anche aggiornare l'app per ogni versione (apparente in iOS 5.1). Il `uuid` non è un valore affidabile. + +### Windows Phone 7 e 8 stranezze + +Il `uuid` per Windows Phone 7 richiede l'autorizzazione `ID_CAP_IDENTITY_DEVICE` . Microsoft probabilmente sarà presto deprecare questa proprietà. Se la funzionalità non è disponibile, l'applicazione genera un guid persistente che viene mantenuto per la durata dell'installazione dell'applicazione sul dispositivo. + +## device.version + +Ottenere la versione del sistema operativo. + + var string = device.version; + + +### Piattaforme supportate + + * Android 2.1 + + * BlackBerry 10 + * Browser + * iOS + * Tizen + * Windows Phone 7 e 8 + * Windows 8 + +### Esempio rapido + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/doc/it/index.md b/mobile/plugins/cordova-plugin-device/doc/it/index.md new file mode 100644 index 0000000..98c6200 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/it/index.md @@ -0,0 +1,206 @@ + + +# cordova-plugin-device + +Questo plugin definisce un global `device` oggetto che descrive il dispositivo hardware e software. Sebbene l'oggetto sia in ambito globale, non è disponibile fino a dopo il `deviceready` evento. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Installazione + + cordova plugin add cordova-plugin-device + + +## Proprietà + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +Ottenere la versione di Cordova in esecuzione nel dispositivo. + +### Piattaforme supportate + +* Amazon fuoco OS +* Android +* BlackBerry 10 +* Browser +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 e 8 +* Windows 8 + +## device.model + +Il `device.model` restituisce il nome del modello del dispositivo o del prodotto. Il valore viene impostato dal produttore del dispositivo e può essere differente tra le versioni dello stesso prodotto. + +### Piattaforme supportate + +* Android +* BlackBerry 10 +* Browser +* iOS +* Tizen +* Windows Phone 7 e 8 +* Windows 8 + +### Esempio rapido + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Vedi http://theiphonewiki.com/wiki/index.php?title=Models / / modello var = device.model; + + +### Stranezze Android + +* Ottiene il [nome del prodotto][1] anziché il [nome del modello][2], che è spesso il nome di codice di produzione. Ad esempio, restituisce il Nexus One `Passion` , e Motorola Droid restituisce`voles`. + + [1]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + [2]: http://developer.android.com/reference/android/os/Build.html#MODEL + +### Tizen stranezze + +* Restituisce il modello di dispositivo assegnato dal fornitore, ad esempio,`TIZEN` + +### Windows Phone 7 e 8 stranezze + +* Restituisce il modello di dispositivo specificato dal produttore. Ad esempio, restituisce il Samsung Focus`SGH-i917`. + +## device.platform + +Ottenere il nome del sistema operativo del dispositivo. + + var string = device.platform; + + +### Piattaforme supportate + +* Android +* BlackBerry 10 +* Browser4 +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 e 8 +* Windows 8 + +### Esempio rapido + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 capricci + +Windows Phone 7 dispositivi segnalano la piattaforma come`WinCE`. + +### Windows Phone 8 stranezze + +Dispositivi Windows Phone 8 segnalano la piattaforma come`Win32NT`. + +## device.uuid + +Ottenere identificatore del dispositivo univoco universale ([UUID][3]). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### Descrizione + +I dettagli di come viene generato un UUID sono determinati dal produttore del dispositivo e sono specifici per la piattaforma o il modello del dispositivo. + +### Piattaforme supportate + +* Android +* BlackBerry 10 +* iOS +* Tizen +* Windows Phone 7 e 8 +* Windows 8 + +### Esempio rapido + + / / Android: restituisce un intero casuale di 64 bit (come stringa, ancora una volta!) / / il numero intero è generato al primo avvio del dispositivo / / / / BlackBerry: restituisce il numero PIN del dispositivo / / questo è un valore integer univoco a nove cifre (come stringa, benchè!) / / / / iPhone: (parafrasato dalla documentazione della classe UIDevice) / / restituisce una stringa di valori hash creata dall'hardware più identifica. + / / È garantito per essere unica per ogni dispositivo e non può essere legato / / per l'account utente. + / / Windows Phone 7: restituisce un hash dell'utente corrente, + dispositivo / / se l'utente non è definito, un guid generato e persisterà fino a quando l'applicazione viene disinstallata / / Tizen: restituisce il dispositivo IMEI (International Mobile Equipment Identity o IMEI è un numero / / unico per ogni cellulare GSM e UMTS. + var deviceID = device.uuid; + + +### iOS Quirk + +Il `uuid` su iOS non è univoco per un dispositivo, ma varia per ogni applicazione, per ogni installazione. Cambia se si elimina e re-installare l'app, e possibilmente anche quando aggiornare iOS o anche aggiornare l'app per ogni versione (apparente in iOS 5.1). Il `uuid` non è un valore affidabile. + +### Windows Phone 7 e 8 stranezze + +Il `uuid` per Windows Phone 7 richiede l'autorizzazione `ID_CAP_IDENTITY_DEVICE` . Microsoft probabilmente sarà presto deprecare questa proprietà. Se la funzionalità non è disponibile, l'applicazione genera un guid persistente che viene mantenuto per la durata dell'installazione dell'applicazione sul dispositivo. + +## device.version + +Ottenere la versione del sistema operativo. + + var string = device.version; + + +### Piattaforme supportate + +* Android 2.1 + +* BlackBerry 10 +* Browser +* iOS +* Tizen +* Windows Phone 7 e 8 +* Windows 8 + +### Esempio rapido + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/doc/ja/README.md b/mobile/plugins/cordova-plugin-device/doc/ja/README.md new file mode 100644 index 0000000..5a345f8 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/ja/README.md @@ -0,0 +1,203 @@ + + +# cordova-plugin-device + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device) + +このプラグインをグローバル定義します `device` オブジェクトは、デバイスのハードウェアとソフトウェアについて説明します。 それは後まで利用可能なオブジェクトがグローバル スコープでは、 `deviceready` イベント。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## インストール + + cordova plugin add cordova-plugin-device + + +## プロパティ + + * device.cordova + * device.model + * device.platform + * device.uuid + * device.version + +## device.cordova + +デバイスで実行されているコルドバのバージョンを取得します。 + +### サポートされているプラットフォーム + + * アマゾン火 OS + * アンドロイド + * ブラックベリー 10 + * ブラウザー + * Firefox の OS + * iOS + * Tizen + * Windows Phone 7 と 8 + * Windows 8 + +## device.model + +`device.model`、デバイスのモデルまたは製品の名前を返します。値は、デバイスの製造元によって設定され、同じ製品のバージョン間で異なる可能性があります。 + +### サポートされているプラットフォーム + + * アンドロイド + * ブラックベリー 10 + * ブラウザー + * iOS + * Tizen + * Windows Phone 7 と 8 + * Windows 8 + +### 簡単な例 + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Http://theiphonewiki.com/wiki/index.php?title=Models を参照してください//var モデル = device.model; + + +### Android の癖 + + * 生産コード名は[モデル名](http://developer.android.com/reference/android/os/Build.html#MODEL)の代わりに[製品名](http://developer.android.com/reference/android/os/Build.html#PRODUCT)を取得します。 たとえば、ネクサス 1 つを返します `Passion` 、Motorola のドロイドを返します`voles`. + +### Tizen の癖 + + * たとえば、ベンダーによって割り当てられているデバイスのモデルを返します`TIZEN` + +### Windows Phone 7 と 8 癖 + + * 製造元によって指定されたデバイスのモデルを返します。たとえば、三星フォーカスを返します`SGH-i917`. + +## device.platform + +デバイスのオペレーティング システム名を取得します。 + + var string = device.platform; + + +### サポートされているプラットフォーム + + * アンドロイド + * ブラックベリー 10 + * Browser4 + * Firefox の OS + * iOS + * Tizen + * Windows Phone 7 と 8 + * Windows 8 + +### 簡単な例 + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 の癖 + +Windows Phone 7 デバイスとプラットフォームを報告します。`WinCE`. + +### Windows Phone 8 癖 + +Windows Phone 8 デバイスとプラットフォームを報告します。`Win32NT`. + +## device.uuid + +デバイスのユニバーサル ・ ユニーク識別子 ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier)を取得します。). + + var string = device.uuid; + + +### 解説 + +UUID を生成する方法の詳細は、デバイスの製造元によって決定され、デバイスのプラットフォームやモデルに固有です。 + +### サポートされているプラットフォーム + + * アンドロイド + * ブラックベリー 10 + * iOS + * Tizen + * Windows Phone 7 と 8 + * Windows 8 + +### 簡単な例 + + //アンドロイド: ランダムな 64 ビットの整数 (を文字列として返します、再び !)/デバイスの最初の起動時に生成される整数/////ブラックベリー: デバイスのピン番号を返します//これは 9 桁の一意な整数 (を文字列としても !)////iPhone: (UIDevice クラスのドキュメントから言い換え)//識別複数のハードウェアから作成されたハッシュ値の文字列を返します。。 + //それはすべてのデバイスに対して一意であることが保証され、接続することはできません//ユーザー アカウント。 + //Windows Phone 7: デバイス + 現在のユーザーのハッシュを返します//ユーザーが定義されていない場合 guid が生成され、アプリがアンインストールされるまで保持されます//Tizen: デバイスの IMEI を返します (国際モバイル機器アイデンティティまたは IMEI は番号です//すべての GSM および UMTS の携帯電話に固有です。 + var deviceID = device.uuid; + + +### iOS の気まぐれ + +`uuid`IOS で、デバイスに固有ではないインストールごと、アプリケーションごとに異なります。 削除、アプリを再インストールした場合に変更と多分またときアップグレード iOS の, またはもアップグレードするアプリ (iOS の 5.1 で明らかに) バージョンごと。 `uuid`は信頼性の高い値ではありません。 + +### Windows Phone 7 と 8 癖 + +`uuid`のために Windows Phone 7 には、権限が必要です `ID_CAP_IDENTITY_DEVICE` 。 Microsoft はすぐにこのプロパティを廃止して可能性があります。 機能が利用できない場合、アプリケーションはデバイスへのアプリケーションのインストールの持続期間のために保持されている永続的な guid を生成します。 + +## device.version + +オペレーティング システムのバージョンを取得します。 + + var string = device.version; + + +### サポートされているプラットフォーム + + * アンドロイド 2.1 + + * ブラックベリー 10 + * ブラウザー + * iOS + * Tizen + * Windows Phone 7 と 8 + * Windows 8 + +### 簡単な例 + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/doc/ja/index.md b/mobile/plugins/cordova-plugin-device/doc/ja/index.md new file mode 100644 index 0000000..b4030fd --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/ja/index.md @@ -0,0 +1,206 @@ + + +# cordova-plugin-device + +このプラグインをグローバル定義します `device` オブジェクトは、デバイスのハードウェアとソフトウェアについて説明します。 それは後まで利用可能なオブジェクトがグローバル スコープでは、 `deviceready` イベント。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## インストール + + cordova plugin add cordova-plugin-device + + +## プロパティ + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +デバイスで実行されているコルドバのバージョンを取得します。 + +### サポートされているプラットフォーム + +* アマゾン火 OS +* アンドロイド +* ブラックベリー 10 +* ブラウザー +* Firefox の OS +* iOS +* Tizen +* Windows Phone 7 と 8 +* Windows 8 + +## device.model + +`device.model`、デバイスのモデルまたは製品の名前を返します。値は、デバイスの製造元によって設定され、同じ製品のバージョン間で異なる可能性があります。 + +### サポートされているプラットフォーム + +* アンドロイド +* ブラックベリー 10 +* ブラウザー +* iOS +* Tizen +* Windows Phone 7 と 8 +* Windows 8 + +### 簡単な例 + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Http://theiphonewiki.com/wiki/index.php?title=Models を参照してください//var モデル = device.model; + + +### Android の癖 + +* 生産コード名は[モデル名][1]の代わりに[製品名][2]を取得します。 たとえば、ネクサス 1 つを返します `Passion` 、Motorola のドロイドを返します`voles`. + + [1]: http://developer.android.com/reference/android/os/Build.html#MODEL + [2]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + +### Tizen の癖 + +* たとえば、ベンダーによって割り当てられているデバイスのモデルを返します`TIZEN` + +### Windows Phone 7 と 8 癖 + +* 製造元によって指定されたデバイスのモデルを返します。たとえば、三星フォーカスを返します`SGH-i917`. + +## device.platform + +デバイスのオペレーティング システム名を取得します。 + + var string = device.platform; + + +### サポートされているプラットフォーム + +* アンドロイド +* ブラックベリー 10 +* Browser4 +* Firefox の OS +* iOS +* Tizen +* Windows Phone 7 と 8 +* Windows 8 + +### 簡単な例 + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 の癖 + +Windows Phone 7 デバイスとプラットフォームを報告します。`WinCE`. + +### Windows Phone 8 癖 + +Windows Phone 8 デバイスとプラットフォームを報告します。`Win32NT`. + +## device.uuid + +デバイスのユニバーサル ・ ユニーク識別子 ([UUID][3]を取得します。). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### 説明 + +UUID を生成する方法の詳細は、デバイスの製造元によって決定され、デバイスのプラットフォームやモデルに固有です。 + +### サポートされているプラットフォーム + +* アンドロイド +* ブラックベリー 10 +* iOS +* Tizen +* Windows Phone 7 と 8 +* Windows 8 + +### 簡単な例 + + //アンドロイド: ランダムな 64 ビットの整数 (を文字列として返します、再び !)/デバイスの最初の起動時に生成される整数/////ブラックベリー: デバイスのピン番号を返します//これは 9 桁の一意な整数 (を文字列としても !)////iPhone: (UIDevice クラスのドキュメントから言い換え)//識別複数のハードウェアから作成されたハッシュ値の文字列を返します。。 + //それはすべてのデバイスに対して一意であることが保証され、接続することはできません//ユーザー アカウント。 + //Windows Phone 7: デバイス + 現在のユーザーのハッシュを返します//ユーザーが定義されていない場合 guid が生成され、アプリがアンインストールされるまで保持されます//Tizen: デバイスの IMEI を返します (国際モバイル機器アイデンティティまたは IMEI は番号です//すべての GSM および UMTS の携帯電話に固有です。 + var deviceID = device.uuid; + + +### iOS の気まぐれ + +`uuid`IOS で、デバイスに固有ではないインストールごと、アプリケーションごとに異なります。 削除、アプリを再インストールした場合に変更と多分またときアップグレード iOS の, またはもアップグレードするアプリ (iOS の 5.1 で明らかに) バージョンごと。 `uuid`は信頼性の高い値ではありません。 + +### Windows Phone 7 と 8 癖 + +`uuid`のために Windows Phone 7 には、権限が必要です `ID_CAP_IDENTITY_DEVICE` 。 Microsoft はすぐにこのプロパティを廃止して可能性があります。 機能が利用できない場合、アプリケーションはデバイスへのアプリケーションのインストールの持続期間のために保持されている永続的な guid を生成します。 + +## device.version + +オペレーティング システムのバージョンを取得します。 + + var string = device.version; + + +### サポートされているプラットフォーム + +* アンドロイド 2.1 + +* ブラックベリー 10 +* ブラウザー +* iOS +* Tizen +* Windows Phone 7 と 8 +* Windows 8 + +### 簡単な例 + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/doc/ko/README.md b/mobile/plugins/cordova-plugin-device/doc/ko/README.md new file mode 100644 index 0000000..a818aac --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/ko/README.md @@ -0,0 +1,203 @@ + + +# cordova-plugin-device + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device) + +이 플러그인 정의 전역 `device` 개체, 디바이스의 하드웨어 및 소프트웨어에 설명 합니다. 개체는 전역 범위에서 비록 그것은 후까지 사용할 수 있는 `deviceready` 이벤트. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## 설치 + + cordova plugin add cordova-plugin-device + + +## 속성 + + * device.cordova + * device.model + * device.platform + * device.uuid + * device.version + +## device.cordova + +코르도바는 장치에서 실행 중인 버전을 얻을. + +### 지원 되는 플랫폼 + + * 아마존 화재 운영 체제 + * 안 드 로이드 + * 블랙베리 10 + * 브라우저 + * Firefox 운영 체제 + * iOS + * Tizen + * Windows Phone 7과 8 + * 윈도우 8 + +## device.model + +`device.model`소자의 모델 또는 제품의 이름을 반환 합니다. 값 장치 제조업체에서 설정 되 고 동일 제품의 버전 간에 다를 수 있습니다. + +### 지원 되는 플랫폼 + + * 안 드 로이드 + * 블랙베리 10 + * 브라우저 + * iOS + * Tizen + * Windows Phone 7과 8 + * 윈도우 8 + +### 빠른 예제 + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Http://theiphonewiki.com/wiki/index.php?title=Models 참조 / / var 모델 = device.model; + + +### 안 드 로이드 단점 + + * 어떤은 종종 프로덕션 코드 이름 대신 [제품 모델 이름](http://developer.android.com/reference/android/os/Build.html#MODEL), [제품 이름](http://developer.android.com/reference/android/os/Build.html#PRODUCT) 을 가져옵니다. 예를 들어 넥서스 하나 반환 합니다 `Passion` , 모토로라 Droid를 반환 합니다`voles`. + +### Tizen 특수 + + * 예를 들어, 공급 업체에 의해 할당 된 디바이스 모델을 반환 합니다.`TIZEN` + +### Windows Phone 7, 8 특수 + + * 제조업체에서 지정 하는 장치 모델을 반환 합니다. 예를 들어 삼성 포커스를 반환 합니다.`SGH-i917`. + +## device.platform + +장치의 운영 체제 이름을 얻을. + + var string = device.platform; + + +### 지원 되는 플랫폼 + + * 안 드 로이드 + * 블랙베리 10 + * Browser4 + * Firefox 운영 체제 + * iOS + * Tizen + * Windows Phone 7과 8 + * 윈도우 8 + +### 빠른 예제 + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 단점 + +Windows Phone 7 장치 보고 플랫폼으로`WinCE`. + +### Windows Phone 8 단점 + +Windows Phone 8 장치 보고 플랫폼으로`Win32NT`. + +## device.uuid + +소자의 보편적으로 고유 식별자 ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier) 를 얻을합니다). + + var string = device.uuid; + + +### 설명 + +UUID 생성 방법의 자세한 내용은 장치 제조업체에 의해 결정 됩니다 및 소자의 플랫폼 이나 모델. + +### 지원 되는 플랫폼 + + * 안 드 로이드 + * 블랙베리 10 + * iOS + * Tizen + * Windows Phone 7과 8 + * 윈도우 8 + +### 빠른 예제 + + / / 안 드 로이드: (문자열로 다시!) 임의의 64 비트 정수를 반환 합니다 / / 정수 장치의 첫 번째 부팅에서 생성 / / / / 블랙베리: 디바이스의 핀 번호를 반환 합니다 / / 이것은 9 자리 고유 정수 (문자열로 비록!) / / / / 아이폰: (UIDevice 클래스 설명서에서 읊 었) / / 문자열 여러 하드웨어에서 생성 하는 해시 값을 식별 하는 반환 합니다. + / 그것은 모든 장치에 대 한 고유 해야 보장 되 고 묶일 수 없습니다 / / / 사용자 계정에. + / / Windows Phone 7: 장치 + 현재 사용자의 해시를 반환 합니다 / / 사용자 정의 되지 않은 경우 guid 생성 되 고 응용 프로그램을 제거할 때까지 유지 됩니다 / / Tizen: 반환 장치 IMEI (국제 모바일 기기 식별 또는 IMEI 숫자입니다 / / 모든 GSM와 UMTS 휴대 전화 고유. + var deviceID = device.uuid; + + +### iOS 특질 + +`uuid`ios 장치에 고유 하지 않습니다 하지만 각 설치에 대 한 응용 프로그램 마다 다릅니다. 삭제 하 고 다시 애플 리 케이 션을 설치 하는 경우 변경 가능 하 게 또한 iOS를 업그레이드 하거나 때 버전 (iOS 5.1에에서 명백한) 당 응용 프로그램 업그레이드도 하 고. `uuid`은 신뢰할 수 있는 값이 아닙니다. + +### Windows Phone 7, 8 특수 + +`uuid`Windows Phone 7 필요 허가 `ID_CAP_IDENTITY_DEVICE` . Microsoft는 곧이 속성을 세웁니다 가능성이 것입니다. 기능을 사용할 수 없는 경우 응용 프로그램 장치에 응용 프로그램의 설치 하는 동안 유지 하는 영구 guid를 생성 합니다. + +## device.version + +운영 체제 버전을 얻을. + + var string = device.version; + + +### 지원 되는 플랫폼 + + * 안 드 로이드 2.1 + + * 블랙베리 10 + * 브라우저 + * iOS + * Tizen + * Windows Phone 7과 8 + * 윈도우 8 + +### 빠른 예제 + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/doc/ko/index.md b/mobile/plugins/cordova-plugin-device/doc/ko/index.md new file mode 100644 index 0000000..0fe38a7 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/ko/index.md @@ -0,0 +1,206 @@ + + +# cordova-plugin-device + +이 플러그인 정의 전역 `device` 개체, 디바이스의 하드웨어 및 소프트웨어에 설명 합니다. 개체는 전역 범위에서 비록 그것은 후까지 사용할 수 있는 `deviceready` 이벤트. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## 설치 + + cordova plugin add cordova-plugin-device + + +## 속성 + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +코르도바는 장치에서 실행 중인 버전을 얻을. + +### 지원 되는 플랫폼 + +* 아마존 화재 운영 체제 +* 안 드 로이드 +* 블랙베리 10 +* 브라우저 +* Firefox 운영 체제 +* iOS +* Tizen +* Windows Phone 7과 8 +* 윈도우 8 + +## device.model + +`device.model`소자의 모델 또는 제품의 이름을 반환 합니다. 값 장치 제조업체에서 설정 되 고 동일 제품의 버전 간에 다를 수 있습니다. + +### 지원 되는 플랫폼 + +* 안 드 로이드 +* 블랙베리 10 +* 브라우저 +* iOS +* Tizen +* Windows Phone 7과 8 +* 윈도우 8 + +### 빠른 예제 + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Http://theiphonewiki.com/wiki/index.php?title=Models 참조 / / var 모델 = device.model; + + +### 안 드 로이드 단점 + +* 어떤은 종종 프로덕션 코드 이름 대신 [제품 모델 이름][1], [제품 이름][2] 을 가져옵니다. 예를 들어 넥서스 하나 반환 합니다 `Passion` , 모토로라 Droid를 반환 합니다`voles`. + + [1]: http://developer.android.com/reference/android/os/Build.html#MODEL + [2]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + +### Tizen 특수 + +* 예를 들어, 공급 업체에 의해 할당 된 디바이스 모델을 반환 합니다.`TIZEN` + +### Windows Phone 7, 8 특수 + +* 제조업체에서 지정 하는 장치 모델을 반환 합니다. 예를 들어 삼성 포커스를 반환 합니다.`SGH-i917`. + +## device.platform + +장치의 운영 체제 이름을 얻을. + + var string = device.platform; + + +### 지원 되는 플랫폼 + +* 안 드 로이드 +* 블랙베리 10 +* Browser4 +* Firefox 운영 체제 +* iOS +* Tizen +* Windows Phone 7과 8 +* 윈도우 8 + +### 빠른 예제 + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 단점 + +Windows Phone 7 장치 보고 플랫폼으로`WinCE`. + +### Windows Phone 8 단점 + +Windows Phone 8 장치 보고 플랫폼으로`Win32NT`. + +## device.uuid + +소자의 보편적으로 고유 식별자 ([UUID][3] 를 얻을합니다). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### 설명 + +UUID 생성 방법의 자세한 내용은 장치 제조업체에 의해 결정 됩니다 및 소자의 플랫폼 이나 모델. + +### 지원 되는 플랫폼 + +* 안 드 로이드 +* 블랙베리 10 +* iOS +* Tizen +* Windows Phone 7과 8 +* 윈도우 8 + +### 빠른 예제 + + / / 안 드 로이드: (문자열로 다시!) 임의의 64 비트 정수를 반환 합니다 / / 정수 장치의 첫 번째 부팅에서 생성 / / / / 블랙베리: 디바이스의 핀 번호를 반환 합니다 / / 이것은 9 자리 고유 정수 (문자열로 비록!) / / / / 아이폰: (UIDevice 클래스 설명서에서 읊 었) / / 문자열 여러 하드웨어에서 생성 하는 해시 값을 식별 하는 반환 합니다. + / 그것은 모든 장치에 대 한 고유 해야 보장 되 고 묶일 수 없습니다 / / / 사용자 계정에. + / / Windows Phone 7: 장치 + 현재 사용자의 해시를 반환 합니다 / / 사용자 정의 되지 않은 경우 guid 생성 되 고 응용 프로그램을 제거할 때까지 유지 됩니다 / / Tizen: 반환 장치 IMEI (국제 모바일 기기 식별 또는 IMEI 숫자입니다 / / 모든 GSM와 UMTS 휴대 전화 고유. + var deviceID = device.uuid; + + +### iOS 특질 + +`uuid`ios 장치에 고유 하지 않습니다 하지만 각 설치에 대 한 응용 프로그램 마다 다릅니다. 삭제 하 고 다시 애플 리 케이 션을 설치 하는 경우 변경 가능 하 게 또한 iOS를 업그레이드 하거나 때 버전 (iOS 5.1에에서 명백한) 당 응용 프로그램 업그레이드도 하 고. `uuid`은 신뢰할 수 있는 값이 아닙니다. + +### Windows Phone 7, 8 특수 + +`uuid`Windows Phone 7 필요 허가 `ID_CAP_IDENTITY_DEVICE` . Microsoft는 곧이 속성을 세웁니다 가능성이 것입니다. 기능을 사용할 수 없는 경우 응용 프로그램 장치에 응용 프로그램의 설치 하는 동안 유지 하는 영구 guid를 생성 합니다. + +## device.version + +운영 체제 버전을 얻을. + + var string = device.version; + + +### 지원 되는 플랫폼 + +* 안 드 로이드 2.1 + +* 블랙베리 10 +* 브라우저 +* iOS +* Tizen +* Windows Phone 7과 8 +* 윈도우 8 + +### 빠른 예제 + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/doc/pl/README.md b/mobile/plugins/cordova-plugin-device/doc/pl/README.md new file mode 100644 index 0000000..c38832d --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/pl/README.md @@ -0,0 +1,214 @@ + + +# cordova-plugin-device + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device) + +Ten plugin określa globalne `device` obiekt, który opisuje urządzenia sprzętowe i programowe. Mimo, że obiekt jest w globalnym zasięgu, nie jest dostępne dopiero po `deviceready` zdarzenie. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Instalacja + + cordova plugin add cordova-plugin-device + + +## Właściwości + + * device.cordova + * device.model + * device.platform + * device.uuid + * device.version + +## device.cordova + +Pobierz wersję Cordova działa na urządzeniu. + +### Obsługiwane platformy + + * Amazon Fire OS + * Android + * BlackBerry 10 + * Przeglądarka + * Firefox OS + * iOS + * Tizen + * Windows Phone 7 i 8 + * Windows 8 + +## device.model + +`device.model`Zwraca nazwę modelu lub produktu. Wartość jest zestaw przez producenta urządzenia i mogą się różnić między wersjami tego samego produktu. + +### Obsługiwane platformy + + * Android + * BlackBerry 10 + * Przeglądarka + * iOS + * Tizen + * Windows Phone 7 i 8 + * Windows 8 + +### Szybki przykład + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Zobacz http://theiphonewiki.com/wiki/index.php?title=Models / / modelu var = device.model; + + +### Dziwactwa Androida + + * Pobiera [nazwę produktu](http://developer.android.com/reference/android/os/Build.html#PRODUCT) zamiast [nazwy modelu](http://developer.android.com/reference/android/os/Build.html#MODEL), który często jest nazwą kod produkcji. Na przykład, Nexus One zwraca `Passion` , i zwraca Motorola Droid`voles`. + +### Dziwactwa Tizen + + * Zwraca modelu urządzenia przypisane przez dostawcę, na przykład,`TIZEN` + +### Windows Phone 7 i 8 dziwactwa + + * Zwraca modelu urządzenia, określonej przez producenta. Na przykład Samsung ostrości zwraca`SGH-i917`. + +## device.platform + +Uzyskać nazwę systemu operacyjnego urządzenia. + + var string = device.platform; + + +### Obsługiwane platformy + + * Android + * BlackBerry 10 + * Browser4 + * Firefox OS + * iOS + * Tizen + * Windows Phone 7 i 8 + * Windows 8 + +### Szybki przykład + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Dziwactwa Windows Phone 7 + +Urządzenia Windows Phone 7 raport platformy jako`WinCE`. + +### Windows Phone 8 dziwactwa + +Urządzenia Windows Phone 8 raport platformy jako`Win32NT`. + +## device.uuid + +Się urządzenia uniwersalnie unikatowy identyfikator ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier)). + + var string = device.uuid; + + +### Opis + +Szczegóły jak UUID jest generowane są określane przez producenta urządzenia i są specyficzne dla platformy lub modelu urządzenia. + +### Obsługiwane platformy + + * Android + * BlackBerry 10 + * iOS + * Tizen + * Windows Phone 7 i 8 + * Windows 8 + +### Szybki przykład + + // Android: Returns a random 64-bit integer (as a string, again!) + // The integer is generated on the device's first boot + // + // BlackBerry: Returns the PIN number of the device + // This is a nine-digit unique integer (as a string, though!) + // + // iPhone: (Paraphrased from the UIDevice Class documentation) + // Returns a string of hash values created from multiple hardware identifies. + // It is guaranteed to be unique for every device and can't be tied + // to the user account. + // Windows Phone 7 : Returns a hash of device+current user, + // if the user is not defined, a guid is generated and will persist until the app is uninstalled + // Tizen: returns the device IMEI (International Mobile Equipment Identity or IMEI is a number + // unique to every GSM and UMTS mobile phone. + var deviceID = device.uuid; + + +### iOS dziwactwo + +`uuid`Na iOS nie jest przypisany do urządzenia, ale różni się dla każdej aplikacji, dla każdej instalacji. Zmienia się jeśli możesz usunąć i ponownie zainstalować aplikację, a ewentualnie także po aktualizacji iOS czy nawet uaktualnienia aplikacji dla wersji (widoczny w iOS 5.1). `uuid`Jest nie wiarygodne wartości. + +### Windows Phone 7 i 8 dziwactwa + +`uuid`Dla Windows Phone 7 wymaga uprawnień `ID_CAP_IDENTITY_DEVICE` . Microsoft będzie prawdopodobnie potępiać ten wkrótce. Jeśli funkcja nie jest dostępna, aplikacja generuje trwałe identyfikator guid, który jest utrzymywany przez czas trwania instalacji aplikacji na urządzeniu. + +## device.version + +Pobierz wersję systemu operacyjnego. + + var string = device.version; + + +### Obsługiwane platformy + + * Android 2.1 + + * BlackBerry 10 + * Przeglądarka + * iOS + * Tizen + * Windows Phone 7 i 8 + * Windows 8 + +### Szybki przykład + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/doc/pl/index.md b/mobile/plugins/cordova-plugin-device/doc/pl/index.md new file mode 100644 index 0000000..acc8f9c --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/pl/index.md @@ -0,0 +1,206 @@ + + +# cordova-plugin-device + +Ten plugin określa globalne `device` obiekt, który opisuje urządzenia sprzętowe i programowe. Mimo, że obiekt jest w globalnym zasięgu, nie jest dostępne dopiero po `deviceready` zdarzenie. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Instalacja + + cordova plugin add cordova-plugin-device + + +## Właściwości + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +Pobierz wersję Cordova działa na urządzeniu. + +### Obsługiwane platformy + +* Amazon Fire OS +* Android +* BlackBerry 10 +* Przeglądarka +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 i 8 +* Windows 8 + +## device.model + +`device.model`Zwraca nazwę modelu lub produktu. Wartość jest zestaw przez producenta urządzenia i mogą się różnić między wersjami tego samego produktu. + +### Obsługiwane platformy + +* Android +* BlackBerry 10 +* Przeglądarka +* iOS +* Tizen +* Windows Phone 7 i 8 +* Windows 8 + +### Szybki przykład + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. Zobacz http://theiphonewiki.com/wiki/index.php?title=Models / / modelu var = device.model; + + +### Dziwactwa Androida + +* Pobiera [nazwę produktu][1] zamiast [nazwy modelu][2], który często jest nazwą kod produkcji. Na przykład, Nexus One zwraca `Passion` , i zwraca Motorola Droid`voles`. + + [1]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + [2]: http://developer.android.com/reference/android/os/Build.html#MODEL + +### Dziwactwa Tizen + +* Zwraca modelu urządzenia przypisane przez dostawcę, na przykład,`TIZEN` + +### Windows Phone 7 i 8 dziwactwa + +* Zwraca modelu urządzenia, określonej przez producenta. Na przykład Samsung ostrości zwraca`SGH-i917`. + +## device.platform + +Uzyskać nazwę systemu operacyjnego urządzenia. + + var string = device.platform; + + +### Obsługiwane platformy + +* Android +* BlackBerry 10 +* Browser4 +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 i 8 +* Windows 8 + +### Szybki przykład + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Dziwactwa Windows Phone 7 + +Urządzenia Windows Phone 7 raport platformy jako`WinCE`. + +### Windows Phone 8 dziwactwa + +Urządzenia Windows Phone 8 raport platformy jako`Win32NT`. + +## device.uuid + +Się urządzenia uniwersalnie unikatowy identyfikator ([UUID][3]). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### Opis + +Szczegóły jak UUID jest generowane są określane przez producenta urządzenia i są specyficzne dla platformy lub modelu urządzenia. + +### Obsługiwane platformy + +* Android +* BlackBerry 10 +* iOS +* Tizen +* Windows Phone 7 i 8 +* Windows 8 + +### Szybki przykład + + / / Android: zwraca losowe 64-bitowa liczba całkowita (jako ciąg, znowu!) / / liczba całkowita jest generowany na pierwszego uruchomienia urządzenia / / / / BlackBerry: zwraca numer PIN urządzenia / / to jest unikatową liczbą całkowitą dziewięciu cyfr (jako ciąg, choć!) / / / / iPhone: (zacytowana w dokumentacji klasy UIDevice) / / zwraca ciąg wartości mieszania utworzone z wielu sprzętu identyfikuje. + Zapewniona jest unikatowy dla każdego urządzenia i nie może być związane z / do konta użytkownika. + / / Windows Phone 7: zwraca wartość mieszania urządzenia + bieżący użytkownik, / / jeśli nie zdefiniowane przez użytkownika, identyfikator guid jest generowany i będzie trwać do czasu odinstalowania aplikacji / / Tizen: zwraca urządzenia IMEI (International Mobile Equipment Identity lub IMEI jest liczbą / / unikatowe dla każdego telefonu komórkowego GSM i UMTS. + var deviceID = device.uuid; + + +### iOS dziwactwo + +`uuid`Na iOS nie jest przypisany do urządzenia, ale różni się dla każdej aplikacji, dla każdej instalacji. Zmienia się jeśli możesz usunąć i ponownie zainstalować aplikację, a ewentualnie także po aktualizacji iOS czy nawet uaktualnienia aplikacji dla wersji (widoczny w iOS 5.1). `uuid`Jest nie wiarygodne wartości. + +### Windows Phone 7 i 8 dziwactwa + +`uuid`Dla Windows Phone 7 wymaga uprawnień `ID_CAP_IDENTITY_DEVICE` . Microsoft będzie prawdopodobnie potępiać ten wkrótce. Jeśli funkcja nie jest dostępna, aplikacja generuje trwałe identyfikator guid, który jest utrzymywany przez czas trwania instalacji aplikacji na urządzeniu. + +## device.version + +Pobierz wersję systemu operacyjnego. + + var string = device.version; + + +### Obsługiwane platformy + +* Android 2.1 + +* BlackBerry 10 +* Przeglądarka +* iOS +* Tizen +* Windows Phone 7 i 8 +* Windows 8 + +### Szybki przykład + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/doc/ru/index.md b/mobile/plugins/cordova-plugin-device/doc/ru/index.md new file mode 100644 index 0000000..263b1cd --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/ru/index.md @@ -0,0 +1,219 @@ + + +# cordova-plugin-device + +Этот плагин определяет глобальный объект `device`, который описывает оборудование и программное обеспечение устройства. Несмотря на то что объект в глобальной области видимости, он не доступен до того момента пока не произойдет событие `deviceready`. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## Установка + + cordova plugin add cordova-plugin-device + + +## Параметры + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +Возвращает версию Cordova, работающую на устройстве. + +### Поддерживаемые платформы + +* Amazon Fire OS +* Android +* BlackBerry 10 +* Обозреватель +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 и 8 +* Windows 8 + +## device.model + +Свойство `device.model` возвращает имя устройства модели или продукта. Значение устанавливается производителем устройства и могут отличаться в разных версиях одного и того же продукта. + +### Поддерживаемые платформы + +* Android +* BlackBerry 10 +* Обозреватель +* iOS +* Tizen +* Windows Phone 7 и 8 +* Windows 8 + +### Краткий пример + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. See http://theiphonewiki.com/wiki/index.php?title=Models + // + var model = device.model; + + +### Особенности Android + +* Возвращает [имя продукта][1] , а не [имя модели][2], которое часто является производственным кодом. Например, Nexus One из них возвращает `Passion` , и Motorola Droid возвращает `voles`. + + [1]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + [2]: http://developer.android.com/reference/android/os/Build.html#MODEL + +### Особенности Tizen + +* Возвращает модель устройства, назначенного вендором, например,`TIZEN` + +### Особенности Windows Phone 7 и 8 + +* Возвращает модель устройства, указанной заводом-изготовителем. Например Samsung Focus возвращает `SGH-i917`. + +## device.platform + +Получите имя операционной системы устройства. + + var string = device.platform; + + +### Поддерживаемые платформы + +* Android +* BlackBerry 10 +* Браузером4 +* Firefox OS +* iOS +* Tizen +* Windows Phone 7 и 8 +* Windows 8 + +### Краткий пример + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Особенности Windows Phone 7 + +Windows Phone 7 устройства сообщают платформу как `WinCE`. + +### Особенности Windows Phone 8 + +Устройства Windows Phone 8 сообщают платформу как `Win32NT`. + +## device.uuid + +Возвращает универсальный уникального идентификатора ([UUID][3] устройства). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### Описание + +Подробная информация о том как UUID генерируется, определяются изготовителем устройства и являются специфическими для платформы или модели устройства. + +### Поддерживаемые платформы + +* Android +* BlackBerry 10 +* iOS +* Tizen +* Windows Phone 7 и 8 +* Windows 8 + +### Краткий пример + + // Android: Возвращает случайное 64-разрядное целое число (в виде строки, опять!) + // целое число генерируется при первой загрузке устройства + // + // BlackBerry: Возвращает номер PIN устройства + // это 9 значный уникальный целочисленный (как строка, хотя!) + // + // iPhone: (Перефразировано из документации класса UIDevice) + // возвращает строку хэш-значения, созданные из нескольких аппаратных определяет. + // Это значение гарантированно является уникальным для каждого устройства и не может быть привязано + // к учетной записи пользователя. + // Windows Phone 7: Возвращает хэш устройство + текущего пользователя, + // если пользователь не определен, формируется guid который и будет сохраняться до тех пор, пока приложение не удалиться + // Tizen: возвращает IMEI устройства (Международный идентификатор мобильного оборудования или IMEI это число + // уникальное для каждого мобильного телефона GSM и UMTS. + var deviceID = device.uuid; + + +### Особенности iOS + +На iOS `uuid` не является уникальным для устройства, но варьируется для каждого приложения, и для каждой установки. Значение меняется, если удалить и повторно установить приложение, и возможно также когда вы обновите iOS, или даже обновить приложение до следующей версии (очевидно в iOS 5.1). Значение `uuid` не является надежным. + +### Особенности Windows Phone 7 и 8 + +Для Windows Phone 7 `uuid` требует разрешения `ID_CAP_IDENTITY_DEVICE` . Microsoft скорее всего скоро сделает это свойство устаревшим. Если возможность недоступна, приложение создает постоянные guid, который сохраняется на все время установки приложения на устройстве. + +## device.version + +Возвращает версию операционной системы. + + var string = device.version; + + +### Поддерживаемые платформы + +* Android 2.1 + +* BlackBerry 10 +* Обозреватель +* iOS +* Tizen +* Windows Phone 7 и 8 +* Windows 8 + +### Краткий пример + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/doc/zh/README.md b/mobile/plugins/cordova-plugin-device/doc/zh/README.md new file mode 100644 index 0000000..9a18a55 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/zh/README.md @@ -0,0 +1,203 @@ + + +# cordova-plugin-device + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-device.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-device) + +這個外掛程式定義全球 `device` 物件,描述該設備的硬體和軟體。 雖然物件是在全球範圍內,但不是可用,直到後 `deviceready` 事件。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## 安裝 + + cordova plugin add cordova-plugin-device + + +## 屬性 + + * device.cordova + * device.model + * device.platform + * device.uuid + * device.version + +## device.cordova + +獲取科爾多瓦在設備上運行的版本。 + +### 支援的平臺 + + * 亞馬遜火 OS + * Android 系統 + * 黑莓 10 + * 瀏覽器 + * 火狐瀏覽器作業系統 + * iOS + * Tizen + * Windows Phone 7 和 8 + * Windows 8 + +## device.model + +`device.model`返回設備的模型或產品的名稱。值由設備製造商設置和同一產品的不同版本可能不同。 + +### 支援的平臺 + + * Android 系統 + * 黑莓 10 + * 瀏覽器 + * iOS + * Tizen + * Windows Phone 7 和 8 + * Windows 8 + +### 快速的示例 + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. 請參閱 HTTP://theiphonewiki.com/wiki/index.php?title=Models / / var 模型 = device.model ; + + +### Android 的怪癖 + + * 獲取[產品名稱](http://developer.android.com/reference/android/os/Build.html#PRODUCT)而不是[產品型號名稱](http://developer.android.com/reference/android/os/Build.html#MODEL),這往往是生產代碼名稱。 例如,Nexus One 返回 `Passion` ,和摩托羅拉 Droid 返回`voles`. + +### Tizen 怪癖 + + * 例如,返回與供應商指派的設備模型`TIZEN` + +### Windows Phone 7 和 8 怪癖 + + * 返回由製造商指定的設備模型。例如,三星焦點返回`SGH-i917`. + +## device.platform + +獲取設備的作業系統名稱。 + + var string = device.platform; + + +### 支援的平臺 + + * Android 系統 + * 黑莓 10 + * Browser4 + * 火狐瀏覽器作業系統 + * iOS + * Tizen + * Windows Phone 7 和 8 + * Windows 8 + +### 快速的示例 + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 的怪癖 + +Windows Phone 7 設備報告作為平臺`WinCE`. + +### Windows Phone 8 怪癖 + +Windows Phone 8 設備報告作為平臺`Win32NT`. + +## device.uuid + +獲取設備的通用唯一識別碼 ([UUID](http://en.wikipedia.org/wiki/Universally_Unique_Identifier)). + + var string = device.uuid; + + +### 說明 + +如何生成一個 UUID 的細節由設備製造商和特定于設備的平臺或模型。 + +### 支援的平臺 + + * Android 系統 + * 黑莓 10 + * iOS + * Tizen + * Windows Phone 7 和 8 + * Windows 8 + +### 快速的示例 + + / / Android: 一個隨機的 64 位整數 (作為字串返回,再次!) / / 上設備的第一次啟動生成的整數 / / / / 黑莓手機: 返回設備的 PIN 號碼 / / 這是九個數字的唯一整數 (作為字串,雖然!) / / / / iPhone: (從 UIDevice 類文檔解釋) / / 返回一個字串的雜湊值創建的多個硬體標識。 + / / 它保證是唯一的每個設備並不能綁 / / 到使用者帳戶。 + / / Windows Phone 7: 返回的雜湊代碼的設備 + 當前使用者,/ / 如果未定義使用者,則一個 guid 生成的並且將會保留直到卸載該應用程式 / / Tizen: 返回設備 IMEI (國際行動裝置身份或 IMEI 是一個數位 / / 獨有的每一個 UMTS 和 GSM 行動電話。 + var deviceID = device.uuid; + + +### iOS 怪癖 + +`uuid`在 iOS 不是唯一的一種裝置,但對於每個應用程式,為每個安裝而異。 如果您刪除並重新安裝該應用程式,它更改和可能還當你升級 iOS,或甚至升級每個版本 (iOS 5.1 中存在明顯的) 的應用程式。 `uuid`不是一個可靠的值。 + +### Windows Phone 7 和 8 怪癖 + +`uuid`為 Windows Phone 7 須經許可 `ID_CAP_IDENTITY_DEVICE` 。 Microsoft 可能會很快棄用此屬性。 如果沒有可用的能力,應用程式將生成設備上應用程式的安裝過程中保持持續的 guid。 + +## device.version + +獲取作業系統版本。 + + var string = device.version; + + +### 支援的平臺 + + * Android 2.1 + + * 黑莓 10 + * 瀏覽器 + * iOS + * Tizen + * Windows Phone 7 和 8 + * Windows 8 + +### 快速的示例 + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-device/doc/zh/index.md b/mobile/plugins/cordova-plugin-device/doc/zh/index.md new file mode 100644 index 0000000..5626d69 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/doc/zh/index.md @@ -0,0 +1,206 @@ + + +# cordova-plugin-device + +這個外掛程式定義全球 `device` 物件,描述該設備的硬體和軟體。 雖然物件是在全球範圍內,但不是可用,直到後 `deviceready` 事件。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(device.cordova); + } + + +## 安裝 + + cordova plugin add cordova-plugin-device + + +## 屬性 + +* device.cordova +* device.model +* device.platform +* device.uuid +* device.version + +## device.cordova + +獲取科爾多瓦在設備上運行的版本。 + +### 支援的平臺 + +* 亞馬遜火 OS +* Android 系統 +* 黑莓 10 +* 瀏覽器 +* 火狐瀏覽器的作業系統 +* iOS +* 泰 +* Windows Phone 7 和 8 +* Windows 8 + +## device.model + +`device.model`返回設備的模型或產品的名稱。值由設備製造商設置和同一產品的不同版本可能不同。 + +### 支援的平臺 + +* Android 系統 +* 黑莓 10 +* 瀏覽器 +* iOS +* 泰 +* Windows Phone 7 和 8 +* Windows 8 + +### 快速的示例 + + // Android: Nexus One returns "Passion" (Nexus One code name) + // Motorola Droid returns "voles" + // BlackBerry: Torch 9800 returns "9800" + // Browser: Google Chrome returns "Chrome" + // Safari returns "Safari" + // iOS: for the iPad Mini, returns iPad2,5; iPhone 5 is iPhone 5,1. 請參閱 HTTP://theiphonewiki.com/wiki/index.php?title=Models / / var 模型 = device.model ; + + +### Android 的怪癖 + +* 獲取[產品名稱][1]而不是[產品型號名稱][2],這往往是生產代碼名稱。 例如,Nexus One 返回 `Passion` ,和摩托羅拉 Droid 返回`voles`. + + [1]: http://developer.android.com/reference/android/os/Build.html#PRODUCT + [2]: http://developer.android.com/reference/android/os/Build.html#MODEL + +### Tizen 怪癖 + +* 例如,返回與供應商指派的設備模型`TIZEN` + +### Windows Phone 7 和 8 怪癖 + +* 返回由製造商指定的設備模型。例如,三星焦點返回`SGH-i917`. + +## device.platform + +獲取設備的作業系統名稱。 + + var string = device.platform; + + +### 支援的平臺 + +* Android 系統 +* 黑莓 10 +* Browser4 +* 火狐瀏覽器的作業系統 +* iOS +* 泰 +* Windows Phone 7 和 8 +* Windows 8 + +### 快速的示例 + + // Depending on the device, a few examples are: + // - "Android" + // - "BlackBerry 10" + // - Browser: returns "MacIntel" on Mac + // returns "Win32" on Windows + // - "iOS" + // - "WinCE" + // - "Tizen" + var devicePlatform = device.platform; + + +### Windows Phone 7 的怪癖 + +Windows Phone 7 設備報告作為平臺`WinCE`. + +### Windows Phone 8 怪癖 + +Windows Phone 8 設備報告作為平臺`Win32NT`. + +## device.uuid + +獲取設備的通用唯一識別碼 ([UUID][3]). + + [3]: http://en.wikipedia.org/wiki/Universally_Unique_Identifier + + var string = device.uuid; + + +### 說明 + +如何生成一個 UUID 的細節由設備製造商和特定于設備的平臺或模型。 + +### 支援的平臺 + +* Android 系統 +* 黑莓 10 +* iOS +* Tizen +* Windows Phone 7 和 8 +* Windows 8 + +### 快速的示例 + + / / Android: 一個隨機的 64 位整數 (作為字串返回,再次!) / / 上設備的第一次啟動生成的整數 / / / / 黑莓手機: 返回設備的 PIN 號碼 / / 這是九個數字的唯一整數 (作為字串,雖然!) / / / / iPhone: (從 UIDevice 類文檔解釋) / / 返回一個字串的雜湊值創建的多個硬體標識。 + / / 它保證是唯一的每個設備並不能綁 / / 到使用者帳戶。 + / / Windows Phone 7: 返回的雜湊代碼的設備 + 當前使用者,/ / 如果未定義使用者,則一個 guid 生成的並且將會保留直到卸載該應用程式 / / Tizen: 返回設備 IMEI (國際行動裝置身份或 IMEI 是一個數位 / / 獨有的每一個 UMTS 和 GSM 行動電話。 + var deviceID = device.uuid; + + +### iOS 怪癖 + +`uuid`在 iOS 不是唯一的一種裝置,但對於每個應用程式,為每個安裝而異。 如果您刪除並重新安裝該應用程式,它更改和可能還當你升級 iOS,或甚至升級每個版本 (iOS 5.1 中存在明顯的) 的應用程式。 `uuid`不是一個可靠的值。 + +### Windows Phone 7 和 8 怪癖 + +`uuid`為 Windows Phone 7 須經許可 `ID_CAP_IDENTITY_DEVICE` 。 Microsoft 可能會很快棄用此屬性。 如果沒有可用的能力,應用程式將生成設備上應用程式的安裝過程中保持持續的 guid。 + +## device.version + +獲取作業系統版本。 + + var string = device.version; + + +### 支援的平臺 + +* Android 2.1 + +* 黑莓 10 +* 瀏覽器 +* iOS +* 泰 +* Windows Phone 7 和 8 +* Windows 8 + +### 快速的示例 + + // Android: Froyo OS would return "2.2" + // Eclair OS would return "2.1", "2.0.1", or "2.0" + // Version can also return update level "2.1-update1" + // + // BlackBerry: Torch 9800 using OS 6.0 would return "6.0.0.600" + // + // Browser: Returns version number for the browser + // + // iPhone: iOS 3.2 returns "3.2" + // + // Windows Phone 7: returns current OS version number, ex. on Mango returns 7.10.7720 + // Tizen: returns "TIZEN_20120425_2" + var deviceVersion = device.version; diff --git a/mobile/plugins/cordova-plugin-device/package.json b/mobile/plugins/cordova-plugin-device/package.json new file mode 100644 index 0000000..12c2d1e --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/package.json @@ -0,0 +1,61 @@ +{ + "name": "cordova-plugin-device", + "version": "1.1.4", + "description": "Cordova Device Plugin", + "cordova": { + "id": "cordova-plugin-device", + "platforms": [ + "firefoxos", + "tizen", + "android", + "amazon-fireos", + "ubuntu", + "ios", + "blackberry10", + "wp7", + "wp8", + "windows8", + "windows", + "browser", + "osx" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/apache/cordova-plugin-device" + }, + "keywords": [ + "cordova", + "device", + "ecosystem:cordova", + "cordova-firefoxos", + "cordova-tizen", + "cordova-android", + "cordova-amazon-fireos", + "cordova-ubuntu", + "cordova-ios", + "cordova-blackberry10", + "cordova-wp7", + "cordova-wp8", + "cordova-windows8", + "cordova-windows", + "cordova-browser", + "cordova-osx" + ], + "scripts": { + "test": "npm run jshint", + "jshint": "node node_modules/jshint/bin/jshint www && node node_modules/jshint/bin/jshint src && node node_modules/jshint/bin/jshint tests" + }, + "author": "Apache Software Foundation", + "license": "Apache-2.0", + "engines": { + "cordovaDependencies": { + "2.0.0": { + "cordova": ">100" + } + } + }, + "devDependencies": { + "jshint": "^2.6.0" + } +} diff --git a/mobile/plugins/cordova-plugin-device/plugin.xml b/mobile/plugins/cordova-plugin-device/plugin.xml new file mode 100644 index 0000000..ae956f8 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/plugin.xml @@ -0,0 +1,174 @@ + + + + + Device + Cordova Device Plugin + Apache 2.0 + cordova,device + https://git-wip-us.apache.org/repos/asf/cordova-plugin-device.git + https://issues.apache.org/jira/browse/CB/component/12320648 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + read_device_identifying_information + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/plugins/cordova-plugin-device/src/android/Device.java b/mobile/plugins/cordova-plugin-device/src/android/Device.java new file mode 100644 index 0000000..e9efcb4 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/android/Device.java @@ -0,0 +1,174 @@ +/* + 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.cordova.device; + +import java.util.TimeZone; + +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.CordovaInterface; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.provider.Settings; + +public class Device extends CordovaPlugin { + public static final String TAG = "Device"; + + public static String platform; // Device OS + public static String uuid; // Device UUID + + private static final String ANDROID_PLATFORM = "Android"; + private static final String AMAZON_PLATFORM = "amazon-fireos"; + private static final String AMAZON_DEVICE = "Amazon"; + + /** + * Constructor. + */ + public Device() { + } + + /** + * Sets the context of the Command. This can then be used to do things like + * get file paths associated with the Activity. + * + * @param cordova The context of the main Activity. + * @param webView The CordovaWebView Cordova is running in. + */ + public void initialize(CordovaInterface cordova, CordovaWebView webView) { + super.initialize(cordova, webView); + Device.uuid = getUuid(); + } + + /** + * Executes the request and returns PluginResult. + * + * @param action The action to execute. + * @param args JSONArry of arguments for the plugin. + * @param callbackContext The callback id used when calling back into JavaScript. + * @return True if the action was valid, false if not. + */ + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + if ("getDeviceInfo".equals(action)) { + JSONObject r = new JSONObject(); + r.put("uuid", Device.uuid); + r.put("version", this.getOSVersion()); + r.put("platform", this.getPlatform()); + r.put("model", this.getModel()); + r.put("manufacturer", this.getManufacturer()); + r.put("isVirtual", this.isVirtual()); + r.put("serial", this.getSerialNumber()); + callbackContext.success(r); + } + else { + return false; + } + return true; + } + + //-------------------------------------------------------------------------- + // LOCAL METHODS + //-------------------------------------------------------------------------- + + /** + * Get the OS name. + * + * @return + */ + public String getPlatform() { + String platform; + if (isAmazonDevice()) { + platform = AMAZON_PLATFORM; + } else { + platform = ANDROID_PLATFORM; + } + return platform; + } + + /** + * Get the device's Universally Unique Identifier (UUID). + * + * @return + */ + public String getUuid() { + String uuid = Settings.Secure.getString(this.cordova.getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); + return uuid; + } + + public String getModel() { + String model = android.os.Build.MODEL; + return model; + } + + public String getProductName() { + String productname = android.os.Build.PRODUCT; + return productname; + } + + public String getManufacturer() { + String manufacturer = android.os.Build.MANUFACTURER; + return manufacturer; + } + + public String getSerialNumber() { + String serial = android.os.Build.SERIAL; + return serial; + } + + /** + * Get the OS version. + * + * @return + */ + public String getOSVersion() { + String osversion = android.os.Build.VERSION.RELEASE; + return osversion; + } + + public String getSDKVersion() { + @SuppressWarnings("deprecation") + String sdkversion = android.os.Build.VERSION.SDK; + return sdkversion; + } + + public String getTimeZoneID() { + TimeZone tz = TimeZone.getDefault(); + return (tz.getID()); + } + + /** + * Function to check if the device is manufactured by Amazon + * + * @return + */ + public boolean isAmazonDevice() { + if (android.os.Build.MANUFACTURER.equals(AMAZON_DEVICE)) { + return true; + } + return false; + } + + public boolean isVirtual() { + return android.os.Build.FINGERPRINT.contains("generic") || + android.os.Build.PRODUCT.contains("sdk"); + } + +} diff --git a/mobile/plugins/cordova-plugin-device/src/blackberry10/index.js b/mobile/plugins/cordova-plugin-device/src/blackberry10/index.js new file mode 100644 index 0000000..ef0543b --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/blackberry10/index.js @@ -0,0 +1,71 @@ +/* + * + * 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. + * +*/ + +/* global PluginResult */ + +function getModelName () { + var modelName = window.qnx.webplatform.device.modelName; + //Pre 10.2 (meaning Z10 or Q10) + if (typeof modelName === "undefined") { + if (window.screen.height === 720 && window.screen.width === 720) { + if ( window.matchMedia("(-blackberry-display-technology: -blackberry-display-oled)").matches) { + modelName = "Q10"; + } else { + modelName = "Q5"; + } + } else if ((window.screen.height === 1280 && window.screen.width === 768) || + (window.screen.height === 768 && window.screen.width === 1280)) { + modelName = "Z10"; + } else { + modelName = window.qnx.webplatform.deviceName; + } + } + + return modelName; +} + +function getUUID () { + var uuid = ""; + try { + //Must surround by try catch because this will throw if the app is missing permissions + uuid = window.qnx.webplatform.device.devicePin; + } catch (e) { + //DO Nothing + } + return uuid; +} + +module.exports = { + getDeviceInfo: function (success, fail, args, env) { + var result = new PluginResult(args, env), + modelName = getModelName(), + uuid = getUUID(), + info = { + manufacturer: 'BlackBerry', + platform: "blackberry10", + version: window.qnx.webplatform.device.scmBundle, + model: modelName, + uuid: uuid + }; + + result.ok(info); + } +}; diff --git a/mobile/plugins/cordova-plugin-device/src/browser/DeviceProxy.js b/mobile/plugins/cordova-plugin-device/src/browser/DeviceProxy.js new file mode 100644 index 0000000..a863201 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/browser/DeviceProxy.js @@ -0,0 +1,82 @@ +/* + * + * 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. + * + */ +var browser = require('cordova/platform'); + +function getPlatform() { + return "browser"; +} + +function getModel() { + return getBrowserInfo(true); +} + +function getVersion() { + return getBrowserInfo(false); +} + +function getBrowserInfo(getModel) { + var userAgent = navigator.userAgent; + var returnVal = ''; + var offset; + + if ((offset = userAgent.indexOf('Chrome')) !== -1) { + returnVal = (getModel) ? 'Chrome' : userAgent.substring(offset + 7); + } else if ((offset = userAgent.indexOf('Safari')) !== -1) { + if (getModel) { + returnVal = 'Safari'; + } else { + returnVal = userAgent.substring(offset + 7); + + if ((offset = userAgent.indexOf('Version')) !== -1) { + returnVal = userAgent.substring(offset + 8); + } + } + } else if ((offset = userAgent.indexOf('Firefox')) !== -1) { + returnVal = (getModel) ? 'Firefox' : userAgent.substring(offset + 8); + } else if ((offset = userAgent.indexOf('MSIE')) !== -1) { + returnVal = (getModel) ? 'MSIE' : userAgent.substring(offset + 5); + } else if ((offset = userAgent.indexOf('Trident')) !== -1) { + returnVal = (getModel) ? 'MSIE' : '11'; + } + + if ((offset = returnVal.indexOf(';')) !== -1 || (offset = returnVal.indexOf(' ')) !== -1) { + returnVal = returnVal.substring(0, offset); + } + + return returnVal; +} + + +module.exports = { + getDeviceInfo: function (success, error) { + setTimeout(function () { + success({ + cordova: browser.cordovaVersion, + platform: getPlatform(), + model: getModel(), + version: getVersion(), + uuid: null + }); + }, 0); + } +}; + +require("cordova/exec/proxy").add("Device", module.exports); diff --git a/mobile/plugins/cordova-plugin-device/src/firefoxos/DeviceProxy.js b/mobile/plugins/cordova-plugin-device/src/firefoxos/DeviceProxy.js new file mode 100644 index 0000000..a05d7ca --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/firefoxos/DeviceProxy.js @@ -0,0 +1,77 @@ +/* + * + * 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. + * + */ +//example UA String for Firefox OS +//Mozilla/5.0 (Mobile; rv:26.0) Gecko/26.0 Firefox/26.0 + +//UA parsing not recommended but currently this is the only way to get the Firefox OS version +//https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference + +//Should be replaced when better conversion to Firefox OS Version is available +function convertVersionNumber(ver) { + var hashVersion = { + '18.0': '1.0.1', + '18.1': '1.1', + '26.0': '1.2', + '28.0': '1.3', + '30.0': '1.4', + '32.0': '2.0' + }; + var rver = ver; + var sStr = ver.substring(0, 4); + if (hashVersion[sStr]) { + rver = hashVersion[sStr]; + } + return (rver); + +} +function getVersion() { + if (navigator.userAgent.match(/(mobile|tablet)/i)) { + var ffVersionArray = (navigator.userAgent.match(/Firefox\/([\d]+\.[\w]?\.?[\w]+)/)); + if (ffVersionArray.length === 2) { + return (convertVersionNumber(ffVersionArray[1])); + } + } + return (null); +} + +function getModel() { + var uaArray = navigator.userAgent.split(/\s*[;)(]\s*/); + if (navigator.userAgent.match(/(mobile|tablet)/i)) { + if (uaArray.length === 5) { + return (uaArray[2]); + } + } + return (null); +} +module.exports = { + getDeviceInfo: function (success, error) { + setTimeout(function () { + success({ + platform: 'firefoxos', + model: getModel(), + version: getVersion(), + uuid: null + }); + }, 0); + } +}; + +require("cordova/exec/proxy").add("Device", module.exports); diff --git a/mobile/plugins/cordova-plugin-device/src/ios/CDVDevice.h b/mobile/plugins/cordova-plugin-device/src/ios/CDVDevice.h new file mode 100644 index 0000000..a146d88 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/ios/CDVDevice.h @@ -0,0 +1,30 @@ +/* + 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. + */ + +#import +#import + +@interface CDVDevice : CDVPlugin +{} + ++ (NSString*)cordovaVersion; + +- (void)getDeviceInfo:(CDVInvokedUrlCommand*)command; + +@end diff --git a/mobile/plugins/cordova-plugin-device/src/ios/CDVDevice.m b/mobile/plugins/cordova-plugin-device/src/ios/CDVDevice.m new file mode 100644 index 0000000..4d75a57 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/ios/CDVDevice.m @@ -0,0 +1,112 @@ +/* + 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. + */ + +#include +#include +#include "TargetConditionals.h" + +#import +#import "CDVDevice.h" + +@implementation UIDevice (ModelVersion) + +- (NSString*)modelVersion +{ + size_t size; + + sysctlbyname("hw.machine", NULL, &size, NULL, 0); + char* machine = malloc(size); + sysctlbyname("hw.machine", machine, &size, NULL, 0); + NSString* platform = [NSString stringWithUTF8String:machine]; + free(machine); + + return platform; +} + +@end + +@interface CDVDevice () {} +@end + +@implementation CDVDevice + +- (NSString*)uniqueAppInstanceIdentifier:(UIDevice*)device +{ + NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; + static NSString* UUID_KEY = @"CDVUUID"; + + // Check user defaults first to maintain backwards compaitibility with previous versions + // which didn't user identifierForVendor + NSString* app_uuid = [userDefaults stringForKey:UUID_KEY]; + if (app_uuid == nil) { + if ([device respondsToSelector:@selector(identifierForVendor)]) { + app_uuid = [[device identifierForVendor] UUIDString]; + } else { + CFUUIDRef uuid = CFUUIDCreate(NULL); + app_uuid = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, uuid); + CFRelease(uuid); + } + + [userDefaults setObject:app_uuid forKey:UUID_KEY]; + [userDefaults synchronize]; + } + + return app_uuid; +} + +- (void)getDeviceInfo:(CDVInvokedUrlCommand*)command +{ + NSDictionary* deviceProperties = [self deviceProperties]; + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:deviceProperties]; + + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; +} + +- (NSDictionary*)deviceProperties +{ + UIDevice* device = [UIDevice currentDevice]; + + return @{ + @"manufacturer": @"Apple", + @"model": [device modelVersion], + @"platform": @"iOS", + @"version": [device systemVersion], + @"uuid": [self uniqueAppInstanceIdentifier:device], + @"cordova": [[self class] cordovaVersion], + @"isVirtual": @([self isVirtual]) + }; +} + ++ (NSString*)cordovaVersion +{ + return CDV_VERSION; +} + +- (BOOL)isVirtual +{ + #if TARGET_OS_SIMULATOR + return true; + #elif TARGET_IPHONE_SIMULATOR + return true; + #else + return false; + #endif +} + +@end diff --git a/mobile/plugins/cordova-plugin-device/src/osx/CDVDevice.h b/mobile/plugins/cordova-plugin-device/src/osx/CDVDevice.h new file mode 100644 index 0000000..9def254 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/osx/CDVDevice.h @@ -0,0 +1,28 @@ +/* + 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. + */ + +#import + +@interface CDVDevice : CDVPlugin + ++ (NSString*) cordovaVersion; + +- (void) getDeviceInfo:(CDVInvokedUrlCommand*)command; + +@end diff --git a/mobile/plugins/cordova-plugin-device/src/osx/CDVDevice.m b/mobile/plugins/cordova-plugin-device/src/osx/CDVDevice.m new file mode 100644 index 0000000..3a63588 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/osx/CDVDevice.m @@ -0,0 +1,113 @@ +/* + 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. + */ + +#include + +#import "CDVDevice.h" + +#define SYSTEM_VERSION_PLIST @"/System/Library/CoreServices/SystemVersion.plist" + +@implementation CDVDevice + +- (NSString*) modelVersion { + size_t size; + + sysctlbyname("hw.machine", NULL, &size, NULL, 0); + char* machine = malloc(size); + sysctlbyname("hw.machine", machine, &size, NULL, 0); + NSString* modelVersion = [NSString stringWithUTF8String:machine]; + free(machine); + + return modelVersion; +} + + +- (NSString*) getSerialNr { + NSString* serialNr; + io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); + if (platformExpert) { + CFTypeRef serialNumberAsCFString = + IORegistryEntryCreateCFProperty(platformExpert, + CFSTR(kIOPlatformSerialNumberKey), + kCFAllocatorDefault, 0); + if (serialNumberAsCFString) { + serialNr = (__bridge NSString*) serialNumberAsCFString; + } + IOObjectRelease(platformExpert); + } + return serialNr; +} + +- (NSString*) uniqueAppInstanceIdentifier { + NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; + static NSString* UUID_KEY = @"CDVUUID"; + + NSString* app_uuid = [userDefaults stringForKey:UUID_KEY]; + + if (app_uuid == nil) { + CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); + CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); + + app_uuid = [NSString stringWithString:(__bridge NSString*) uuidString]; + [userDefaults setObject:app_uuid forKey:UUID_KEY]; + [userDefaults synchronize]; + + CFRelease(uuidString); + CFRelease(uuidRef); + } + + return app_uuid; +} + +- (NSString*) platform { + return [NSDictionary dictionaryWithContentsOfFile:SYSTEM_VERSION_PLIST][@"ProductName"]; +} + +- (NSString*) systemVersion { + return [NSDictionary dictionaryWithContentsOfFile:SYSTEM_VERSION_PLIST][@"ProductVersion"]; +} + +- (void) getDeviceInfo:(CDVInvokedUrlCommand*) command { + NSDictionary* deviceProperties = [self deviceProperties]; + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:deviceProperties]; + + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; +} + +- (NSDictionary*) deviceProperties { + NSMutableDictionary* devProps = [NSMutableDictionary dictionaryWithCapacity:4]; + + devProps[@"manufacturer"] = @"Apple"; + devProps[@"model"] = [self modelVersion]; + devProps[@"platform"] = [self platform]; + devProps[@"version"] = [self systemVersion]; + devProps[@"uuid"] = [self uniqueAppInstanceIdentifier]; + devProps[@"cordova"] = [[self class] cordovaVersion]; + devProps[@"serial"] = [self getSerialNr]; + devProps[@"isVirtual"] = @NO; + + NSDictionary* devReturn = [NSDictionary dictionaryWithDictionary:devProps]; + return devReturn; +} + ++ (NSString*) cordovaVersion { + return CDV_VERSION; +} + +@end diff --git a/mobile/plugins/cordova-plugin-device/src/tizen/DeviceProxy.js b/mobile/plugins/cordova-plugin-device/src/tizen/DeviceProxy.js new file mode 100644 index 0000000..973b716 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/tizen/DeviceProxy.js @@ -0,0 +1,38 @@ +/* + * + * 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. + * +*/ + +var tizen = require('cordova/platform'); + +module.exports = { + getDeviceInfo: function(success, error) { + setTimeout(function () { + success({ + cordova: tizen.cordovaVersion, + platform: 'tizen', + model: null, + version: null, + uuid: null + }); + }, 0); + } +}; + +require("cordova/tizen/commandProxy").add("Device", module.exports); diff --git a/mobile/plugins/cordova-plugin-device/src/ubuntu/device.cpp b/mobile/plugins/cordova-plugin-device/src/ubuntu/device.cpp new file mode 100644 index 0000000..eb5a012 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/ubuntu/device.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ + * + * Licensed 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. + */ + +#include +#include + +#include"device.h" + +#define CORDOVA "3.0.0" + +Device::Device(Cordova *cordova) : CPlugin(cordova) { +} + +static QString getOSName() { +#ifdef Q_OS_SYMBIAN + QString platform = "Symbian"; +#endif +#ifdef Q_OS_WIN + QString platform = "Windows"; +#endif +#ifdef Q_OS_WINCE + QString platform = "Windows CE"; +#endif +#ifdef Q_OS_LINUX + QString platform = "Linux"; +#endif + return platform; +} + +void Device::getInfo(int scId, int ecId) { + Q_UNUSED(ecId) + + QDeviceInfo systemDeviceInfo; + QDeviceInfo systemInfo; + + QString platform = getOSName(); + + QString uuid = systemDeviceInfo.uniqueDeviceID(); + if (uuid.isEmpty()) { + QString deviceDescription = systemInfo.imei(0) + ";" + systemInfo.manufacturer() + ";" + systemInfo.model() + ";" + systemInfo.productName() + ";" + platform; + QString user = qgetenv("USER"); + if (user.isEmpty()) { + user = qgetenv("USERNAME"); + if (user.isEmpty()) + user = QDir::homePath(); + } + uuid = QString(QCryptographicHash::hash((deviceDescription + ";" + user).toUtf8(), QCryptographicHash::Md5).toHex()); + } + + this->cb(scId, systemDeviceInfo.model(), CORDOVA, platform, uuid, systemInfo.version(QDeviceInfo::Os)); +} diff --git a/mobile/plugins/cordova-plugin-device/src/ubuntu/device.h b/mobile/plugins/cordova-plugin-device/src/ubuntu/device.h new file mode 100644 index 0000000..91cb937 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/ubuntu/device.h @@ -0,0 +1,47 @@ +/* + * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ + * + * Licensed 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. + */ + +#ifndef DEVICE_H_FDSAFAS +#define DEVICE_H_FDSAFAS + +#include + +#include + +class Device: public CPlugin { + Q_OBJECT +public: + explicit Device(Cordova *cordova); + + virtual const QString fullName() override { + return Device::fullID(); + } + + virtual const QString shortName() override { + return "Device"; + } + + static const QString fullID() { + return "com.cordova.Device"; + } + +signals: + +public slots: + void getInfo(int scId, int ecId); +}; + +#endif diff --git a/mobile/plugins/cordova-plugin-device/src/ubuntu/device.js b/mobile/plugins/cordova-plugin-device/src/ubuntu/device.js new file mode 100644 index 0000000..838586c --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/ubuntu/device.js @@ -0,0 +1,33 @@ +/* + * + * 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. + * +*/ + +/* global Cordova */ + +module.exports = { + getInfo:function(win,fail,args) { + Cordova.exec(function (model, cordova, platform, uuid, version) { + win({name: name, model: model, cordova: cordova, + platform: platform, uuid: uuid, version: version}); + }, null, "com.cordova.Device", "getInfo", []); + } +}; + +require("cordova/exec/proxy").add("Device", module.exports); diff --git a/mobile/plugins/cordova-plugin-device/src/windows/DeviceProxy.js b/mobile/plugins/cordova-plugin-device/src/windows/DeviceProxy.js new file mode 100644 index 0000000..f338ad3 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/windows/DeviceProxy.js @@ -0,0 +1,98 @@ +/* + * + * 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. + * +*/ + +/* global Windows, createUUID */ + +var ROOT_CONTAINER = "{00000000-0000-0000-FFFF-FFFFFFFFFFFF}"; +var DEVICE_CLASS_KEY = "{A45C254E-DF1C-4EFD-8020-67D146A850E0},10"; +var DEVICE_CLASS_KEY_NO_SEMICOLON = "{A45C254E-DF1C-4EFD-8020-67D146A850E0}10"; +var ROOT_CONTAINER_QUERY = "System.Devices.ContainerId:=\"" + ROOT_CONTAINER + "\""; +var HAL_DEVICE_CLASS = "4d36e966-e325-11ce-bfc1-08002be10318"; +var DEVICE_DRIVER_VERSION_KEY = "{A8B865DD-2E3D-4094-AD97-E593A70C75D6},3"; + +module.exports = { + + getDeviceInfo:function(win, fail, args) { + + // deviceId aka uuid, stored in Windows.Storage.ApplicationData.current.localSettings.values.deviceId + var deviceId; + // get deviceId, or create and store one + var localSettings = Windows.Storage.ApplicationData.current.localSettings; + if (localSettings.values.deviceId) { + deviceId = localSettings.values.deviceId; + } + else { + // App-specific hardware id could be used as uuid, but it changes if the hardware changes... + try { + var ASHWID = Windows.System.Profile.HardwareIdentification.getPackageSpecificToken(null).id; + deviceId = Windows.Storage.Streams.DataReader.fromBuffer(ASHWID).readGuid(); + } catch (e) { + // Couldn't get the hardware UUID + deviceId = createUUID(); + } + //...so cache it per-install + localSettings.values.deviceId = deviceId; + } + + + var userAgent = window.clientInformation.userAgent; + // this will report "windows" in windows8.1 and windows phone 8.1 apps + // and "windows8" in windows 8.0 apps similar to cordova.js + // See https://github.com/apache/cordova-js/blob/master/src/windows/platform.js#L25 + var devicePlatform = userAgent.indexOf("MSAppHost/1.0") == -1 ? "windows" : "windows8"; + var versionString = userAgent.match(/Windows (?:Phone |NT )?([0-9.]+)/)[1]; + + var deviceInfo = new Windows.Security.ExchangeActiveSyncProvisioning.EasClientDeviceInformation(); + // Running in the Windows Simulator is a remote session. + // Running in the Windows Phone Emulator has the systemProductName set to "Virtual" + var isVirtual = Windows.System.RemoteDesktop.InteractiveSession.isRemote || deviceInfo.systemProductName == "Virtual"; + var manufacturer = deviceInfo.systemManufacturer; + var model = deviceInfo.systemProductName; + + var Pnp = Windows.Devices.Enumeration.Pnp; + + Pnp.PnpObject.findAllAsync(Pnp.PnpObjectType.device, + [DEVICE_DRIVER_VERSION_KEY, DEVICE_CLASS_KEY], + ROOT_CONTAINER_QUERY) + .then(function (rootDevices) { + for (var i = 0; i < rootDevices.length; i++) { + var rootDevice = rootDevices[i]; + if (!rootDevice.properties) continue; + if (rootDevice.properties[DEVICE_CLASS_KEY_NO_SEMICOLON] == HAL_DEVICE_CLASS) { + versionString = rootDevice.properties[DEVICE_DRIVER_VERSION_KEY]; + break; + } + } + + setTimeout(function () { + win({ platform: devicePlatform, + version: versionString, + uuid: deviceId, + isVirtual: isVirtual, + model: model, + manufacturer:manufacturer}); + }, 0); + }); + } + +}; // exports + +require("cordova/exec/proxy").add("Device", module.exports); diff --git a/mobile/plugins/cordova-plugin-device/src/wp/Device.cs b/mobile/plugins/cordova-plugin-device/src/wp/Device.cs new file mode 100644 index 0000000..76fe8cf --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/src/wp/Device.cs @@ -0,0 +1,87 @@ +/* + Licensed 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. +*/ + +using Microsoft.Phone.Info; +using System; +using System.IO; +using System.IO.IsolatedStorage; + +namespace WPCordovaClassLib.Cordova.Commands +{ + public class Device : BaseCommand + { + public void getDeviceInfo(string notused) + { + string res = String.Format("\"name\":\"{0}\",\"platform\":\"{1}\",\"uuid\":\"{2}\",\"version\":\"{3}\",\"model\":\"{4}\",\"manufacturer\":\"{5}\",\"isVirtual\":{6}", + DeviceStatus.DeviceName, + Environment.OSVersion.Platform.ToString(), + UUID, + Environment.OSVersion.Version.ToString(), + DeviceStatus.DeviceName, + DeviceStatus.DeviceManufacturer, + IsVirtual ? "true" : "false"); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "{" + res + "}")); + } + + + public bool IsVirtual + { + get + { + return (Microsoft.Devices.Environment.DeviceType == Microsoft.Devices.DeviceType.Emulator); + } + } + + public string UUID + { + get + { + object id; + + UserExtendedProperties.TryGetValue("ANID", out id); + if (id != null) + { + return id.ToString().Substring(2, 32); + } + + UserExtendedProperties.TryGetValue("ANID2", out id); + if (id != null) + { + return id.ToString(); + } + + string returnVal = "???unknown???"; + + using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication()) + { + try + { + IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Open, FileAccess.Read, appStorage); + + using (StreamReader reader = new StreamReader(fileStream)) + { + returnVal = reader.ReadLine(); + } + } + catch (Exception /*ex*/) + { + + } + } + + return returnVal; + } + } + } +} diff --git a/mobile/plugins/cordova-plugin-device/tests/plugin.xml b/mobile/plugins/cordova-plugin-device/tests/plugin.xml new file mode 100644 index 0000000..4efeaf6 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/tests/plugin.xml @@ -0,0 +1,31 @@ + + + + + Cordova Device Plugin Tests + Apache 2.0 + + + + diff --git a/mobile/plugins/cordova-plugin-device/tests/tests.js b/mobile/plugins/cordova-plugin-device/tests/tests.js new file mode 100644 index 0000000..ac9a281 --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/tests/tests.js @@ -0,0 +1,113 @@ +/* + * + * 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. + * +*/ + +/* jshint jasmine: true */ + +exports.defineAutoTests = function() { + describe('Device Information (window.device)', function () { + it("should exist", function() { + expect(window.device).toBeDefined(); + }); + + it("should contain a platform specification that is a string", function() { + expect(window.device.platform).toBeDefined(); + expect((String(window.device.platform)).length > 0).toBe(true); + }); + + it("should contain a version specification that is a string", function() { + expect(window.device.version).toBeDefined(); + expect((String(window.device.version)).length > 0).toBe(true); + }); + + it("should contain a UUID specification that is a string or a number", function() { + expect(window.device.uuid).toBeDefined(); + if (typeof window.device.uuid == 'string' || typeof window.device.uuid == 'object') { + expect((String(window.device.uuid)).length > 0).toBe(true); + } else { + expect(window.device.uuid > 0).toBe(true); + } + }); + + it("should contain a cordova specification that is a string", function() { + expect(window.device.cordova).toBeDefined(); + expect((String(window.device.cordova)).length > 0).toBe(true); + }); + + it("should depend on the presence of cordova.version string", function() { + expect(window.cordova.version).toBeDefined(); + expect((String(window.cordova.version)).length > 0).toBe(true); + }); + + it("should contain device.cordova equal to cordova.version", function() { + expect(window.device.cordova).toBe(window.cordova.version); + }); + + it("should contain a model specification that is a string", function() { + expect(window.device.model).toBeDefined(); + expect((String(window.device.model)).length > 0).toBe(true); + }); + + it("should contain a manufacturer property that is a string", function() { + expect(window.device.manufacturer).toBeDefined(); + expect((String(window.device.manufacturer)).length > 0).toBe(true); + }); + + it("should contain an isVirtual property that is a boolean", function() { + expect(window.device.isVirtual).toBeDefined(); + expect(typeof window.device.isVirtual).toBe("boolean"); + }); + + it("should contain a serial number specification that is a string", function() { + expect(window.device.serial).toBeDefined(); + expect((String(window.device.serial)).length > 0).toBe(true); + + }); + + }); +}; + +exports.defineManualTests = function(contentEl, createActionButton) { + var logMessage = function (message, color) { + var log = document.getElementById('info'); + var logLine = document.createElement('div'); + if (color) { + logLine.style.color = color; + } + logLine.innerHTML = message; + log.appendChild(logLine); + }; + + var clearLog = function () { + var log = document.getElementById('info'); + log.innerHTML = ''; + }; + + var device_tests = '

Press Dump Device button to get device information

' + + '
' + + 'Expected result: Status box will get updated with device info. (i.e. platform, version, uuid, model, etc)'; + + contentEl.innerHTML = '
' + device_tests; + + createActionButton('Dump device', function() { + clearLog(); + logMessage(JSON.stringify(window.device, null, '\t')); + }, "dump_device"); +}; diff --git a/mobile/plugins/cordova-plugin-device/www/device.js b/mobile/plugins/cordova-plugin-device/www/device.js new file mode 100644 index 0000000..f7ed19f --- /dev/null +++ b/mobile/plugins/cordova-plugin-device/www/device.js @@ -0,0 +1,83 @@ +/* + * + * 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. + * +*/ + +var argscheck = require('cordova/argscheck'), + channel = require('cordova/channel'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + cordova = require('cordova'); + +channel.createSticky('onCordovaInfoReady'); +// Tell cordova channel to wait on the CordovaInfoReady event +channel.waitForInitialization('onCordovaInfoReady'); + +/** + * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the + * phone, etc. + * @constructor + */ +function Device() { + this.available = false; + this.platform = null; + this.version = null; + this.uuid = null; + this.cordova = null; + this.model = null; + this.manufacturer = null; + this.isVirtual = null; + this.serial = null; + + var me = this; + + channel.onCordovaReady.subscribe(function() { + me.getInfo(function(info) { + //ignoring info.cordova returning from native, we should use value from cordova.version defined in cordova.js + //TODO: CB-5105 native implementations should not return info.cordova + var buildLabel = cordova.version; + me.available = true; + me.platform = info.platform; + me.version = info.version; + me.uuid = info.uuid; + me.cordova = buildLabel; + me.model = info.model; + me.isVirtual = info.isVirtual; + me.manufacturer = info.manufacturer || 'unknown'; + me.serial = info.serial || 'unknown'; + channel.onCordovaInfoReady.fire(); + },function(e) { + me.available = false; + utils.alert("[ERROR] Error initializing Cordova: " + e); + }); + }); +} + +/** + * Get device info + * + * @param {Function} successCallback The function to call when the heading data is available + * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL) + */ +Device.prototype.getInfo = function(successCallback, errorCallback) { + argscheck.checkArgs('fF', 'Device.getInfo', arguments); + exec(successCallback, errorCallback, "Device", "getDeviceInfo", []); +}; + +module.exports = new Device(); diff --git a/mobile/plugins/cordova-plugin-file/CONTRIBUTING.md b/mobile/plugins/cordova-plugin-file/CONTRIBUTING.md new file mode 100644 index 0000000..4c8e6a5 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/CONTRIBUTING.md @@ -0,0 +1,37 @@ + + +# Contributing to Apache Cordova + +Anyone can contribute to Cordova. And we need your contributions. + +There are multiple ways to contribute: report bugs, improve the docs, and +contribute code. + +For instructions on this, start with the +[contribution overview](http://cordova.apache.org/contribute/). + +The details are explained there, but the important items are: + - Sign and submit an Apache ICLA (Contributor License Agreement). + - Have a Jira issue open that corresponds to your contribution. + - Run the tests so your patch doesn't break existing functionality. + +We look forward to your contributions! diff --git a/mobile/plugins/cordova-plugin-file/LICENSE b/mobile/plugins/cordova-plugin-file/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/NOTICE b/mobile/plugins/cordova-plugin-file/NOTICE new file mode 100644 index 0000000..8ec56a5 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/NOTICE @@ -0,0 +1,5 @@ +Apache Cordova +Copyright 2012 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). diff --git a/mobile/plugins/cordova-plugin-file/README.md b/mobile/plugins/cordova-plugin-file/README.md new file mode 100644 index 0000000..8a50749 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/README.md @@ -0,0 +1,868 @@ +--- +title: File +description: Read/write files on the device. +--- + + +|Android|iOS| Windows 8.1 Store | Windows 8.1 Phone | Windows 10 Store | Travis CI | +|:-:|:-:|:-:|:-:|:-:|:-:| +|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-file)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-file/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-file)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-file/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-file)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-file/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-file)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-file/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-file)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-file/)|[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-file)| + +# cordova-plugin-file + +This plugin implements a File API allowing read/write access to files residing on the device. + +This plugin is based on several specs, including : +The HTML5 File API +[http://www.w3.org/TR/FileAPI/](http://www.w3.org/TR/FileAPI/) + +The Directories and System extensions +Latest: +[http://www.w3.org/TR/2012/WD-file-system-api-20120417/](http://www.w3.org/TR/2012/WD-file-system-api-20120417/) +Although most of the plugin code was written when an earlier spec was current: +[http://www.w3.org/TR/2011/WD-file-system-api-20110419/](http://www.w3.org/TR/2011/WD-file-system-api-20110419/) + +It also implements the FileWriter spec : +[http://dev.w3.org/2009/dap/file-system/file-writer.html](http://dev.w3.org/2009/dap/file-system/file-writer.html) + +>*Note* While the W3C FileSystem spec is deprecated for web browsers, the FileSystem APIs are supported in Cordova applications with this plugin for the platforms listed in the _Supported Platforms_ list, with the exception of the Browser platform. + +To get a few ideas how to use the plugin, check out the [sample](#sample) at the bottom of this page. For additional examples (browser focused), see the HTML5 Rocks' [FileSystem article.](http://www.html5rocks.com/en/tutorials/file/filesystem/) + +For an overview of other storage options, refer to Cordova's +[storage guide](http://cordova.apache.org/docs/en/latest/cordova/storage/storage.html). + +This plugin defines global `cordova.file` object. + +Although in the global scope, it is not available until after the `deviceready` event. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + +Report issues on the [Apache Cordova issue tracker](https://issues.apache.org/jira/issues/?jql=project%20%3D%20CB%20AND%20status%20in%20%28Open%2C%20%22In%20Progress%22%2C%20Reopened%29%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20%22Plugin%20File%22%20ORDER%20BY%20priority%20DESC%2C%20summary%20ASC%2C%20updatedDate%20DESC) + +## Installation + + cordova plugin add cordova-plugin-file + +## Supported Platforms + +- Amazon Fire OS +- Android +- BlackBerry 10 +- Firefox OS +- iOS +- OS X +- Windows Phone 7 and 8* +- Windows 8* +- Windows* +- Browser + +\* _These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`._ + +## Where to Store Files + +As of v1.2.0, URLs to important file-system directories are provided. +Each URL is in the form _file:///path/to/spot/_, and can be converted to a +`DirectoryEntry` using `window.resolveLocalFileSystemURL()`. + +* `cordova.file.applicationDirectory` - Read-only directory where the application + is installed. (_iOS_, _Android_, _BlackBerry 10_, _OSX_, _windows_) + +* `cordova.file.applicationStorageDirectory` - Root directory of the application's + sandbox; on iOS & windows this location is read-only (but specific subdirectories [like + `/Documents` on iOS or `/localState` on windows] are read-write). All data contained within + is private to the app. (_iOS_, _Android_, _BlackBerry 10_, _OSX_) + +* `cordova.file.dataDirectory` - Persistent and private data storage within the + application's sandbox using internal memory (on Android, if you need to use + external memory, use `.externalDataDirectory`). On iOS, this directory is not + synced with iCloud (use `.syncedDataDirectory`). (_iOS_, _Android_, _BlackBerry 10_, _windows_) + +* `cordova.file.cacheDirectory` - Directory for cached data files or any files + that your app can re-create easily. The OS may delete these files when the device + runs low on storage, nevertheless, apps should not rely on the OS to delete files + in here. (_iOS_, _Android_, _BlackBerry 10_, _OSX_, _windows_) + +* `cordova.file.externalApplicationStorageDirectory` - Application space on + external storage. (_Android_) + +* `cordova.file.externalDataDirectory` - Where to put app-specific data files on + external storage. (_Android_) + +* `cordova.file.externalCacheDirectory` - Application cache on external storage. + (_Android_) + +* `cordova.file.externalRootDirectory` - External storage (SD card) root. (_Android_, _BlackBerry 10_) + +* `cordova.file.tempDirectory` - Temp directory that the OS can clear at will. Do not + rely on the OS to clear this directory; your app should always remove files as + applicable. (_iOS_, _OSX_, _windows_) + +* `cordova.file.syncedDataDirectory` - Holds app-specific files that should be synced + (e.g. to iCloud). (_iOS_, _windows_) + +* `cordova.file.documentsDirectory` - Files private to the app, but that are meaningful + to other application (e.g. Office files). Note that for _OSX_ this is the user's `~/Documents` directory. (_iOS_, _OSX_) + +* `cordova.file.sharedDirectory` - Files globally available to all applications (_BlackBerry 10_) + +## File System Layouts + +Although technically an implementation detail, it can be very useful to know how +the `cordova.file.*` properties map to physical paths on a real device. + +### iOS File System Layout + +| Device Path | `cordova.file.*` | `iosExtraFileSystems` | r/w? | persistent? | OS clears | sync | private | +|:-----------------------------------------------|:----------------------------|:----------------------|:----:|:-----------:|:---------:|:----:|:-------:| +| `/var/mobile/Applications//` | applicationStorageDirectory | - | r | N/A | N/A | N/A | Yes | +|    `appname.app/` | applicationDirectory | bundle | r | N/A | N/A | N/A | Yes | +|       `www/` | - | - | r | N/A | N/A | N/A | Yes | +|    `Documents/` | documentsDirectory | documents | r/w | Yes | No | Yes | Yes | +|       `NoCloud/` | - | documents-nosync | r/w | Yes | No | No | Yes | +|    `Library` | - | library | r/w | Yes | No | Yes? | Yes | +|       `NoCloud/` | dataDirectory | library-nosync | r/w | Yes | No | No | Yes | +|       `Cloud/` | syncedDataDirectory | - | r/w | Yes | No | Yes | Yes | +|       `Caches/` | cacheDirectory | cache | r/w | Yes* | Yes\*\*\*| No | Yes | +|    `tmp/` | tempDirectory | - | r/w | No\*\* | Yes\*\*\*| No | Yes | + + + \* Files persist across app restarts and upgrades, but this directory can + be cleared whenever the OS desires. Your app should be able to recreate any + content that might be deleted. + +\*\* Files may persist across app restarts, but do not rely on this behavior. Files + are not guaranteed to persist across updates. Your app should remove files from + this directory when it is applicable, as the OS does not guarantee when (or even + if) these files are removed. + +\*\*\* The OS may clear the contents of this directory whenever it feels it is + necessary, but do not rely on this. You should clear this directory as + appropriate for your application. + +### Android File System Layout + +| Device Path | `cordova.file.*` | `AndroidExtraFileSystems` | r/w? | persistent? | OS clears | private | +|:------------------------------------------------|:----------------------------|:--------------------------|:----:|:-----------:|:---------:|:-------:| +| `file:///android_asset/` | applicationDirectory | assets | r | N/A | N/A | Yes | +| `/data/data//` | applicationStorageDirectory | - | r/w | N/A | N/A | Yes | +|    `cache` | cacheDirectory | cache | r/w | Yes | Yes\* | Yes | +|    `files` | dataDirectory | files | r/w | Yes | No | Yes | +|       `Documents` | | documents | r/w | Yes | No | Yes | +| `/` | externalRootDirectory | sdcard | r/w | Yes | No | No | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Yes | No | No | +|       `cache` | externalCacheDirectry | cache-external | r/w | Yes | No\*\*| No | +|       `files` | externalDataDirectory | files-external | r/w | Yes | No | No | + +\* The OS may periodically clear this directory, but do not rely on this behavior. Clear + the contents of this directory as appropriate for your application. Should a user + purge the cache manually, the contents of this directory are removed. + +\*\* The OS does not clear this directory automatically; you are responsible for managing + the contents yourself. Should the user purge the cache manually, the contents of the + directory are removed. + +**Note**: If external storage can't be mounted, the `cordova.file.external*` +properties are `null`. + +### BlackBerry 10 File System Layout + +| Device Path | `cordova.file.*` | r/w? | persistent? | OS clears | private | +|:-------------------------------------------------------------|:----------------------------|:----:|:-----------:|:---------:|:-------:| +| `file:///accounts/1000/appdata//` | applicationStorageDirectory | r | N/A | N/A | Yes | +|    `app/native` | applicationDirectory | r | N/A | N/A | Yes | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | No | Yes | Yes | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Yes | No | Yes | +| `file:///accounts/1000/removable/sdcard` | externalRemovableDirectory | r/w | Yes | No | No | +| `file:///accounts/1000/shared` | sharedDirectory | r/w | Yes | No | No | + +*Note*: When application is deployed to work perimeter, all paths are relative to /accounts/1000-enterprise. + +### OS X File System Layout + +| Device Path | `cordova.file.*` | `iosExtraFileSystems` | r/w? | OS clears | private | +|:-------------------------------------------------|:----------------------------|:----------------------|:----:|:---------:|:-------:| +| `/Applications/.app/` | - | bundle | r | N/A | Yes | +|     `Content/Resources/` | applicationDirectory | - | r | N/A | Yes | +| `~/Library/Application Support//` | applicationStorageDirectory | - | r/w | No | Yes | +|     `files/` | dataDirectory | - | r/w | No | Yes | +| `~/Documents/` | documentsDirectory | documents | r/w | No | No | +| `~/Library/Caches//` | cacheDirectory | cache | r/w | No | Yes | +| `/tmp/` | tempDirectory | - | r/w | Yes\* | Yes | +| `/` | rootDirectory | root | r/w | No\*\* | No | + +**Note**: This is the layout for non sandboxed applications. I you enable sandboxing, the `applicationStorageDirectory` will be below ` ~/Library/Containers//Data/Library/Application Support`. + +\* Files persist across app restarts and upgrades, but this directory can + be cleared whenever the OS desires. Your app should be able to recreate any + content that might be deleted. You should clear this directory as + appropriate for your application. + +\*\* Allows access to the entire file system. This is only available for non sandboxed apps. + +### Windows File System Layout + +| Device Path | `cordova.file.*` | r/w? | persistent? | OS clears | private | +|:------------------------------------------------------|:----------------------------|:----:|:-----------:|:---------:|:-------:| +| `ms-appdata:///` | applicationDirectory | r | N/A | N/A | Yes | +|    `local/` | dataDirectory | r/w | Yes | No | Yes | +|    `temp/` | cacheDirectory | r/w | No | Yes\* | Yes | +|    `temp/` | tempDirectory | r/w | No | Yes\* | Yes | +|    `roaming/` | syncedDataDirectory | r/w | Yes | No | Yes | + +\* The OS may periodically clear this directory + + +## Android Quirks + +### Android Persistent storage location + +There are multiple valid locations to store persistent files on an Android +device. See [this page](http://developer.android.com/guide/topics/data/data-storage.html) +for an extensive discussion of the various possibilities. + +Previous versions of the plugin would choose the location of the temporary and +persistent files on startup, based on whether the device claimed that the SD +Card (or equivalent storage partition) was mounted. If the SD Card was mounted, +or if a large internal storage partition was available (such as on Nexus +devices,) then the persistent files would be stored in the root of that space. +This meant that all Cordova apps could see all of the files available on the +card. + +If the SD card was not available, then previous versions would store data under +`/data/data/`, which isolates apps from each other, but may still +cause data to be shared between users. + +It is now possible to choose whether to store files in the internal file +storage location, or using the previous logic, with a preference in your +application's `config.xml` file. To do this, add one of these two lines to +`config.xml`: + + + + + +Without this line, the File plugin will use `Internal` as the default. If +a preference tag is present, and is not one of these values, the application +will not start. + +If your application has previously been shipped to users, using an older (pre- +3.0.0) version of this plugin, and has stored files in the persistent filesystem, +then you should set the preference to `Compatibility` if your config.xml does not specify a location for the persistent filesystem. Switching the location to +"Internal" would mean that existing users who upgrade their application may be +unable to access their previously-stored files, depending on their device. + +If your application is new, or has never previously stored files in the +persistent filesystem, then the `Internal` setting is generally recommended. + +### Slow recursive operations for /android_asset + +Listing asset directories is really slow on Android. You can speed it up though, by +adding `src/android/build-extras.gradle` to the root of your android project (also +requires cordova-android@4.0.0 or greater). + +### Permisson to write to external storage when it's not mounted on Marshmallow + +Marshmallow requires the apps to ask for permissions when reading/writing to external locations. By +[default](http://developer.android.com/guide/topics/data/data-storage.html#filesExternal), your app has permission to write to +`cordova.file.applicationStorageDirectory` and `cordova.file.externalApplicationStorageDirectory`, and the plugin doesn't request permission +for these two directories unless external storage is not mounted. However due to a limitation, when external storage is not mounted, it would ask for +permission to write to `cordova.file.externalApplicationStorageDirectory`. + +## iOS Quirks + +- `cordova.file.applicationStorageDirectory` is read-only; attempting to store + files within the root directory will fail. Use one of the other `cordova.file.*` + properties defined for iOS (only `applicationDirectory` and `applicationStorageDirectory` are + read-only). +- `FileReader.readAsText(blob, encoding)` + - The `encoding` parameter is not supported, and UTF-8 encoding is always in effect. + +### iOS Persistent storage location + +There are two valid locations to store persistent files on an iOS device: the +Documents directory and the Library directory. Previous versions of the plugin +only ever stored persistent files in the Documents directory. This had the +side-effect of making all of an application's files visible in iTunes, which +was often unintended, especially for applications which handle lots of small +files, rather than producing complete documents for export, which is the +intended purpose of the directory. + +It is now possible to choose whether to store files in the documents or library +directory, with a preference in your application's `config.xml` file. To do this, +add one of these two lines to `config.xml`: + + + + + +Without this line, the File plugin will use `Compatibility` as the default. If +a preference tag is present, and is not one of these values, the application +will not start. + +If your application has previously been shipped to users, using an older (pre- +1.0) version of this plugin, and has stored files in the persistent filesystem, +then you should set the preference to `Compatibility`. Switching the location to +`Library` would mean that existing users who upgrade their application would be +unable to access their previously-stored files. + +If your application is new, or has never previously stored files in the +persistent filesystem, then the `Library` setting is generally recommended. + +## Firefox OS Quirks + +The File System API is not natively supported by Firefox OS and is implemented +as a shim on top of indexedDB. + +* Does not fail when removing non-empty directories +* Does not support metadata for directories +* Methods `copyTo` and `moveTo` do not support directories + +The following data paths are supported: +* `applicationDirectory` - Uses `xhr` to get local files that are packaged with the app. +* `dataDirectory` - For persistent app-specific data files. +* `cacheDirectory` - Cached files that should survive app restarts (Apps should not rely +on the OS to delete files in here). + +## Browser Quirks + +### Common quirks and remarks +- Each browser uses its own sandboxed filesystem. IE and Firefox use IndexedDB as a base. +All browsers use forward slash as directory separator in a path. +- Directory entries have to be created successively. +For example, the call `fs.root.getDirectory('dir1/dir2', {create:true}, successCallback, errorCallback)` +will fail if dir1 did not exist. +- The plugin requests user permission to use persistent storage at the application first start. +- Plugin supports `cdvfile://localhost` (local resources) only. I.e. external resources are not supported via `cdvfile`. +- The plugin does not follow ["File System API 8.3 Naming restrictions"](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions). +- Blob and File' `close` function is not supported. +- `FileSaver` and `BlobBuilder` are not supported by this plugin and don't have stubs. +- The plugin does not support `requestAllFileSystems`. This function is also missing in the specifications. +- Entries in directory will not be removed if you use `create: true` flag for existing directory. +- Files created via constructor are not supported. You should use entry.file method instead. +- Each browser uses its own form for blob URL references. +- `readAsDataURL` function is supported, but the mediatype in Chrome depends on entry name extension, +mediatype in IE is always empty (which is the same as `text-plain` according the specification), +the mediatype in Firefox is always `application/octet-stream`. +For example, if the content is `abcdefg` then Firefox returns `data:application/octet-stream;base64,YWJjZGVmZw==`, +IE returns `data:;base64,YWJjZGVmZw==`, Chrome returns `data:;base64,YWJjZGVmZw==`. +- `toInternalURL` returns the path in the form `file:///persistent/path/to/entry` (Firefox, IE). +Chrome returns the path in the form `cdvfile://localhost/persistent/file`. + +### Chrome quirks +- Chrome filesystem is not immediately ready after device ready event. As a workaround you can subscribe to `filePluginIsReady` event. +Example: +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` +You can use `window.isFilePluginReadyRaised` function to check whether event was already raised. +- window.requestFileSystem TEMPORARY and PERSISTENT filesystem quotas are not limited in Chrome. +- To increase persistent storage in Chrome you need to call `window.initPersistentFileSystem` method. Persistent storage quota is 5 MB by default. +- Chrome requires `--allow-file-access-from-files` run argument to support API via `file:///` protocol. +- `File` object will be not changed if you use flag `{create:true}` when getting an existing `Entry`. +- events `cancelable` property is set to true in Chrome. This is contrary to the [specification](http://dev.w3.org/2009/dap/file-system/file-writer.html). +- `toURL` function in Chrome returns `filesystem:`-prefixed path depending on application host. +For example, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. +- `toURL` function result does not contain trailing slash in case of directory entry. +Chrome resolves directories with slash-trailed urls correctly though. +- `resolveLocalFileSystemURL` method requires the inbound `url` to have `filesystem` prefix. For example, `url` parameter for `resolveLocalFileSystemURL` +should be in the form `filesystem:file:///persistent/somefile.txt` as opposed to the form `file:///persistent/somefile.txt` in Android. +- Deprecated `toNativeURL` function is not supported and does not have a stub. +- `setMetadata` function is not stated in the specifications and not supported. +- INVALID_MODIFICATION_ERR (code: 9) is thrown instead of SYNTAX_ERR(code: 8) on requesting of a non-existant filesystem. +- INVALID_MODIFICATION_ERR (code: 9) is thrown instead of PATH_EXISTS_ERR(code: 12) on trying to exclusively create a file or directory, which already exists. +- INVALID_MODIFICATION_ERR (code: 9) is thrown instead of NO_MODIFICATION_ALLOWED_ERR(code: 6) on trying to call removeRecursively on the root file system. +- INVALID_MODIFICATION_ERR (code: 9) is thrown instead of NOT_FOUND_ERR(code: 1) on trying to moveTo directory that does not exist. + +### IndexedDB-based impl quirks (Firefox and IE) +- `.` and `..` are not supported. +- IE does not support `file:///`-mode; only hosted mode is supported (http://localhost:xxxx). +- Firefox filesystem size is not limited but each 50MB extension will request a user permission. +IE10 allows up to 10mb of combined AppCache and IndexedDB used in implementation of filesystem without prompting, +once you hit that level you will be asked if you want to allow it to be increased up to a max of 250mb per site. +So `size` parameter for `requestFileSystem` function does not affect filesystem in Firefox and IE. +- `readAsBinaryString` function is not stated in the Specs and not supported in IE and does not have a stub. +- `file.type` is always null. +- You should not create entry using DirectoryEntry instance callback result which was deleted. +Otherwise, you will get a 'hanging entry'. +- Before you can read a file, which was just written you need to get a new instance of this file. +- `setMetadata` function, which is not stated in the Specs supports `modificationTime` field change only. +- `copyTo` and `moveTo` functions do not support directories. +- Directories metadata is not supported. +- Both Entry.remove and directoryEntry.removeRecursively don't fail when removing +non-empty directories - directories being removed are cleaned along with contents instead. +- `abort` and `truncate` functions are not supported. +- progress events are not fired. For example, this handler will be not executed: +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## Upgrading Notes + +In v1.0.0 of this plugin, the `FileEntry` and `DirectoryEntry` structures have changed, +to be more in line with the published specification. + +Previous (pre-1.0.0) versions of the plugin stored the device-absolute-file-location +in the `fullPath` property of `Entry` objects. These paths would typically look like + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + +These paths were also returned by the `toURL()` method of the `Entry` objects. + +With v1.0.0, the `fullPath` attribute is the path to the file, _relative to the root of +the HTML filesystem_. So, the above paths would now both be represented by a `FileEntry` +object with a `fullPath` of + + /path/to/file + +If your application works with device-absolute-paths, and you previously retrieved those +paths through the `fullPath` property of `Entry` objects, then you should update your code +to use `entry.toURL()` instead. + +For backwards compatibility, the `resolveLocalFileSystemURL()` method will accept a +device-absolute-path, and will return an `Entry` object corresponding to it, as long as that +file exists within either the `TEMPORARY` or `PERSISTENT` filesystems. + +This has particularly been an issue with the File-Transfer plugin, which previously used +device-absolute-paths (and can still accept them). It has been updated to work correctly +with FileSystem URLs, so replacing `entry.fullPath` with `entry.toURL()` should resolve any +issues getting that plugin to work with files on the device. + +In v1.1.0 the return value of `toURL()` was changed (see [CB-6394](https://issues.apache.org/jira/browse/CB-6394)) +to return an absolute 'file://' URL. wherever possible. To ensure a 'cdvfile:'-URL you can use `toInternalURL()` now. +This method will now return filesystem URLs of the form + + cdvfile://localhost/persistent/path/to/file + +which can be used to identify the file uniquely. + +## cdvfile protocol +**Purpose** + +`cdvfile://localhost/persistent|temporary|another-fs-root*/path/to/file` can be used for platform-independent file paths. +cdvfile paths are supported by core plugins - for example you can download an mp3 file to cdvfile-path via `cordova-plugin-file-transfer` and play it via `cordova-plugin-media`. + +__*Note__: See [Where to Store Files](#where-to-store-files), [File System Layouts](#file-system-layouts) and [Configuring the Plugin](#configuring-the-plugin-optional) for more details about available fs roots. + +To use `cdvfile` as a tag' `src` you can convert it to native path via `toURL()` method of the resolved fileEntry, which you can get via `resolveLocalFileSystemURL` - see examples below. + +You can also use `cdvfile://` paths directly in the DOM, for example: +```HTML + +``` + +__Note__: This method requires following Content Security rules updates: +* Add `cdvfile:` scheme to `Content-Security-Policy` meta tag of the index page, e.g.: + - `` +* Add `` to `config.xml`. + +**Converting cdvfile:// to native path** + +```javascript +resolveLocalFileSystemURL('cdvfile://localhost/temporary/path/to/file.mp4', function(entry) { + var nativePath = entry.toURL(); + console.log('Native URI: ' + nativePath); + document.getElementById('video').src = nativePath; +``` + +**Converting native path to cdvfile://** + +```javascript +resolveLocalFileSystemURL(nativePath, function(entry) { + console.log('cdvfile URI: ' + entry.toInternalURL()); +``` + +**Using cdvfile in core plugins** + +```javascript +fileTransfer.download(uri, 'cdvfile://localhost/temporary/path/to/file.mp3', function (entry) { ... +``` +```javascript +var my_media = new Media('cdvfile://localhost/temporary/path/to/file.mp3', ...); +my_media.play(); +``` + +#### cdvfile quirks +- Using `cdvfile://` paths in the DOM is not supported on Windows platform (a path can be converted to native instead). + + +## List of Error Codes and Meanings +When an error is thrown, one of the following codes will be used. + +| Code | Constant | +|-----:|:------------------------------| +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Configuring the Plugin (Optional) + +The set of available filesystems can be configured per-platform. Both iOS and +Android recognize a tag in `config.xml` which names the +filesystems to be installed. By default, all file-system roots are enabled. + + + + +### Android + +* `files`: The application's internal file storage directory +* `files-external`: The application's external file storage directory +* `sdcard`: The global external file storage directory (this is the root of the SD card, if one is installed). You must have the `android.permission.WRITE_EXTERNAL_STORAGE` permission to use this. +* `cache`: The application's internal cache directory +* `cache-external`: The application's external cache directory +* `assets`: The application's bundle (read-only) +* `root`: The entire device filesystem + +Android also supports a special filesystem named "documents", which represents a "/Documents/" subdirectory within the "files" filesystem. + +### iOS + +* `library`: The application's Library directory +* `documents`: The application's Documents directory +* `cache`: The application's Cache directory +* `bundle`: The application's bundle; the location of the app itself on disk (read-only) +* `root`: The entire device filesystem + +By default, the library and documents directories can be synced to iCloud. You can also request two additional filesystems, `library-nosync` and `documents-nosync`, which represent a special non-synced directory within the `/Library` or `/Documents` filesystem. + +## Sample: Create Files and Directories, Write, Read, and Append files + +The File plugin allows you to do things like store files in a temporary or persistent storage location for your app (sandboxed storage) and to store files in other platform-dependent locations. The code snippets in this section demonstrate different tasks including: +* [Accessing the file system](#persistent) +* Using cross-platform Cordova file URLs to [store your files](#appendFile) (see _Where to Store Files_ for more info) +* Creating [files](#persistent) and [directories](#createDir) +* [Writing to files](#writeFile) +* [Reading files](#readFile) +* [Appending files](#appendFile) +* [Display an image file](#displayImage) + +## Create a persistent file + +Before you use the File plugin APIs, you can get access to the file system using `requestFileSystem`. When you do this, you can request either persistent or temporary storage. Persistent storage will not be removed unless permission is granted by the user. + +When you get file system access using `requestFileSystem`, access is granted for the sandboxed file system only (the sandbox limits access to the app itself), not for general access to any file system location on the device. (To access file system locations outside the sandboxed storage, use other methods such as window.requestLocalFileSystemURL, which support platform-specific locations. For one example of this, see _Append a File_.) + +Here is a request for persistent storage. + +>*Note* When targeting WebView clients (instead of a browser) or native apps (Windows), you dont need to use `requestQuota` before using persistent storage. + +```js +window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) { + + console.log('file system open: ' + fs.name); + fs.root.getFile("newPersistentFile.txt", { create: true, exclusive: false }, function (fileEntry) { + + console.log("fileEntry is file?" + fileEntry.isFile.toString()); + // fileEntry.name == 'someFile.txt' + // fileEntry.fullPath == '/someFile.txt' + writeFile(fileEntry, null); + + }, onErrorCreateFile); + +}, onErrorLoadFs); +``` + +The success callback receives FileSystem object (fs). Use `fs.root` to return a DirectoryEntry object, which you can use to create or get a file (by calling `getFile`). In this example, `fs.root` is a DirectoryEntry object that represents the persistent storage in the sandboxed file system. + +The success callback for `getFile` receives a FileEntry object. You can use this to perform file write and file read operations. + +## Create a temporary file + +Here is an example of a request for temporary storage. Temporary storage may be deleted by the operating system if the device runs low on memory. + +```js +window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs) { + + console.log('file system open: ' + fs.name); + createFile(fs.root, "newTempFile.txt", false); + +}, onErrorLoadFs); +``` +When you are using temporary storage, you can create or get the file by calling `getFile`. As in the persistent storage example, this will give you a FileEntry object that you can use for read or write operations. + +```js +function createFile(dirEntry, fileName, isAppend) { + // Creates a new file or returns the file if it already exists. + dirEntry.getFile(fileName, {create: true, exclusive: false}, function(fileEntry) { + + writeFile(fileEntry, null, isAppend); + + }, onErrorCreateFile); + +} +``` + +## Write to a file + +Once you have a FileEntry object, you can write to the file by calling `createWriter`, which returns a FileWriter object in the success callback. Call the `write` method of FileWriter to write to the file. + +```js +function writeFile(fileEntry, dataObj) { + // Create a FileWriter object for our FileEntry (log.txt). + fileEntry.createWriter(function (fileWriter) { + + fileWriter.onwriteend = function() { + console.log("Successful file write..."); + readFile(fileEntry); + }; + + fileWriter.onerror = function (e) { + console.log("Failed file write: " + e.toString()); + }; + + // If data object is not passed in, + // create a new Blob instead. + if (!dataObj) { + dataObj = new Blob(['some file data'], { type: 'text/plain' }); + } + + fileWriter.write(dataObj); + }); +} +``` + +## Read a file + +You also need a FileEntry object to read an existing file. Use the file property of FileEntry to get the file reference, and then create a new FileReader object. You can use methods like `readAsText` to start the read operation. When the read operation is complete, `this.result` stores the result of the read operation. + +```js +function readFile(fileEntry) { + + fileEntry.file(function (file) { + var reader = new FileReader(); + + reader.onloadend = function() { + console.log("Successful file read: " + this.result); + displayFileData(fileEntry.fullPath + ": " + this.result); + }; + + reader.readAsText(file); + + }, onErrorReadFile); +} +``` + +## Append a file using alternative methods + +Of course, you will often want to append existing files instead of creating new ones. Here is an example of that. This example shows another way that you can access the file system using window.resolveLocalFileSystemURL. In this example, pass the cross-platform Cordova file URL, cordova.file.dataDirectory, to the function. The success callback receives a DirectoryEntry object, which you can use to do things like create a file. + +```js +window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function (dirEntry) { + console.log('file system open: ' + dirEntry.name); + var isAppend = true; + createFile(dirEntry, "fileToAppend.txt", isAppend); +}, onErrorLoadFs); +``` + +In addition to this usage, you can use `resolveLocalFileSystemURL` to get access to some file system locations that are not part of the sandboxed storage system. See _Where to store Files_ for more information; many of these storage locations are platform-specific. You can also pass cross-platform file system locations to `resolveLocalFileSystemURL` using the _cdvfile protocol_. + +For the append operation, there is nothing new in the `createFile` function that is called in the preceding code (see the preceding examples for the actual code). `createFile` calls `writeFile`. In `writeFile`, you check whether an append operation is requested. + +Once you have a FileWriter object, call the `seek` method, and pass in the index value for the position where you want to write. In this example, you also test whether the file exists. After calling seek, then call the write method of FileWriter. + +```js +function writeFile(fileEntry, dataObj, isAppend) { + // Create a FileWriter object for our FileEntry (log.txt). + fileEntry.createWriter(function (fileWriter) { + + fileWriter.onwriteend = function() { + console.log("Successful file read..."); + readFile(fileEntry); + }; + + fileWriter.onerror = function (e) { + console.log("Failed file read: " + e.toString()); + }; + + // If we are appending data to file, go to the end of the file. + if (isAppend) { + try { + fileWriter.seek(fileWriter.length); + } + catch (e) { + console.log("file doesn't exist!"); + } + } + fileWriter.write(dataObj); + }); +} +``` + +## Store an existing binary file + +We already showed how to write to a file that you just created in the sandboxed file system. What if you need to get access to an existing file and convert that to something you can store on your device? In this example, you obtain a file using an xhr request, and then save it to the cache in the sandboxed file system. + +Before you get the file, get a FileSystem reference using `requestFileSystem`. By passing window.TEMPORARY in the method call (same as before), the returned FileSystem object (fs) represents the cache in the sandboxed file system. Use `fs.root` to get the DirectoryEntry object that you need. + +```js +window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs) { + + console.log('file system open: ' + fs.name); + getSampleFile(fs.root); + +}, onErrorLoadFs); +``` + +For completeness, here is the xhr request to get a Blob image. There is nothing Cordova-specific in this code, except that you forward the DirectoryEntry reference that you already obtained as an argument to the saveFile function. You will save the blob image and display it later after reading the file (to validate the operation). + +```js +function getSampleFile(dirEntry) { + + var xhr = new XMLHttpRequest(); + xhr.open('GET', 'http://cordova.apache.org/static/img/cordova_bot.png', true); + xhr.responseType = 'blob'; + + xhr.onload = function() { + if (this.status == 200) { + + var blob = new Blob([this.response], { type: 'image/png' }); + saveFile(dirEntry, blob, "downloadedImage.png"); + } + }; + xhr.send(); +} +``` +>*Note* For Cordova 5 security, the preceding code requires that you add the domain name, http://cordova.apache.org, to the Content-Security-Policy element in index.html. + +After getting the file, copy the contents to a new file. The current DirectoryEntry object is already associated with the app cache. + +```js +function saveFile(dirEntry, fileData, fileName) { + + dirEntry.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) { + + writeFile(fileEntry, fileData); + + }, onErrorCreateFile); +} +``` + +In writeFile, you pass in the Blob object as the dataObj and you will save that in the new file. + +```js +function writeFile(fileEntry, dataObj, isAppend) { + + // Create a FileWriter object for our FileEntry (log.txt). + fileEntry.createWriter(function (fileWriter) { + + fileWriter.onwriteend = function() { + console.log("Successful file write..."); + if (dataObj.type == "image/png") { + readBinaryFile(fileEntry); + } + else { + readFile(fileEntry); + } + }; + + fileWriter.onerror = function(e) { + console.log("Failed file write: " + e.toString()); + }; + + fileWriter.write(dataObj); + }); +} +``` + +After writing to the file, read it and display it. You saved the image as binary data, so you can read it using FileReader.readAsArrayBuffer. + +```js +function readBinaryFile(fileEntry) { + + fileEntry.file(function (file) { + var reader = new FileReader(); + + reader.onloadend = function() { + + console.log("Successful file write: " + this.result); + displayFileData(fileEntry.fullPath + ": " + this.result); + + var blob = new Blob([new Uint8Array(this.result)], { type: "image/png" }); + displayImage(blob); + }; + + reader.readAsArrayBuffer(file); + + }, onErrorReadFile); +} +``` + +After reading the data, you can display the image using code like this. Use window.URL.createObjectURL to get a DOM string for the Blob image. + +```js +function displayImage(blob) { + + // Displays image if result is a valid DOM string for an image. + var elem = document.getElementById('imageFile'); + // Note: Use window.URL.revokeObjectURL when finished with image. + elem.src = window.URL.createObjectURL(blob); +} +``` + +## Display an image file + +To display an image using a FileEntry, you can call the `toURL` method. + +```js +function displayImageByFileURL(fileEntry) { + var elem = document.getElementById('imageFile'); + elem.src = fileEntry.toURL(); +} +``` + +If you are using some platform-specific URIs instead of a FileEntry and you want to display an image, you may need to include the main part of the URI in the Content-Security-Policy element in index.html. For example, on Windows 10, you can include `ms-appdata:` in your element. Here is an example. + +```html + +``` + +## Create Directories + +In the code here, you create directories in the root of the app storage location. You could use this code with any writable storage location (that is, any DirectoryEntry). Here, you write to the application cache (assuming that you used window.TEMPORARY to get your FileSystem object) by passing fs.root into this function. + +This code creates the /NewDirInRoot/images folder in the application cache. For platform-specific values, look at _File System Layouts_. + +```js +function createDirectory(rootDirEntry) { + rootDirEntry.getDirectory('NewDirInRoot', { create: true }, function (dirEntry) { + dirEntry.getDirectory('images', { create: true }, function (subDirEntry) { + + createFile(subDirEntry, "fileInNewSubDir.txt"); + + }, onErrorGetDir); + }, onErrorGetDir); +} +``` + +When creating subfolders, you need to create each folder separately as shown in the preceding code. diff --git a/mobile/plugins/cordova-plugin-file/RELEASENOTES.md b/mobile/plugins/cordova-plugin-file/RELEASENOTES.md new file mode 100644 index 0000000..fd57274 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/RELEASENOTES.md @@ -0,0 +1,444 @@ + +# Release Notes + +### 4.3.1 (Dec 07, 2016) +* [CB-12112](https://issues.apache.org/jira/browse/CB-12112) windows: Make available to move folder trees +* fix ENCODING_ERR for applicationDirectory +* [CB-11848](https://issues.apache.org/jira/browse/CB-11848) windows: Remove duplicate slash after file system path +* [CB-11917](https://issues.apache.org/jira/browse/CB-11917) - Remove pull request template checklist item: "iCLA has been submitted…" +* [CB-11947](https://issues.apache.org/jira/browse/CB-11947) fixed typo that occurs when adding file-transfer plugin +* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Incremented plugin version. + +### 4.3.0 (Sep 08, 2016) +* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to cordovaDependencies +* Add handling for `SecurityException` +* [CB-11368](https://issues.apache.org/jira/browse/CB-11368) **android**: Resolve content `URLs` produced by contacts plugin +* Plugin uses `Android Log class` and not `Cordova LOG class` +* [CB-11693](https://issues.apache.org/jira/browse/CB-11693) **ios**: Run copy and move operations in the background thread +* [CB-11699](https://issues.apache.org/jira/browse/CB-11699) Read files as Data URLs properly +* [CB-11305](https://issues.apache.org/jira/browse/CB-11305) Enable `cdvfile: assets fs root` for `DOM` requests +* [CB-11385](https://issues.apache.org/jira/browse/CB-11385) android: Import java.nio.charset.Charset in LocalFileSystem class +* Add badges for paramedic builds on Jenkins +* [CB-11407](https://issues.apache.org/jira/browse/CB-11407) ios: added extern keyword to constants to fix phonegap-webview-ios template issue. +* [CB-11385](https://issues.apache.org/jira/browse/CB-11385) **android**: Does not pass sonarqube scan +* Add pull request template. +* Minor edits to the `README.md` +* [CB-11142](https://issues.apache.org/jira/browse/CB-11142) Fix the `NeedPermission` code for the case when external media is not mounted in Android +* [CB-11003](https://issues.apache.org/jira/browse/CB-11003) Adding samples to Readme. +* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to README.md +* [CB-11115](https://issues.apache.org/jira/browse/CB-11115) **android**: Removing dependency on FileDescriptor toString in content provider tests + +### 4.2.0 (Apr 15, 2016) +* [CB-10960](https://issues.apache.org/jira/browse/CB-10960) Uncaught `#` in `write()` when `readyState != WRITING ?` +* Replace `PermissionHelper.java` with `cordova-plugin-compat` +* [CB-10977](https://issues.apache.org/jira/browse/CB-10977) **Android** Removing global state used for permission requests +* CB-10798, [CB-10384](https://issues.apache.org/jira/browse/CB-10384) Fixing permissions for **Marshmallow**. +* Fix test failure on **WP 8.1** +* [CB-10577](https://issues.apache.org/jira/browse/CB-10577) **Windows** `resolveLocalFileSystemURL` should omit trailing slash for file +* [CB-7862](https://issues.apache.org/jira/browse/CB-7862) `FileReader` reads large files in chunks with progress. +* [CB-10577](https://issues.apache.org/jira/browse/CB-10577) **Android** `resolveLocalFileSystemURL` should detect directory vs file. +* [CB-9753](https://issues.apache.org/jira/browse/CB-9753) index out of bounds on `requestFileSystem`. +* Remove `warning` emoji, as it doesn't correctly display in the docs website: cordova.apache.org/docs/en/dev/cordova-plugin-file/index.html. This closes #166 +* [CB-10636](https://issues.apache.org/jira/browse/CB-10636) Add `JSHint` for plugins +* [CB-10411](https://issues.apache.org/jira/browse/CB-10411) Error in `file.spec.129` of `cordova-plugin-file` + +### 4.1.1 (Feb 09, 2016) +* Edit package.json license to match SPDX id +* [CB-10419](https://issues.apache.org/jira/browse/CB-10419) cordova-plugin-file 4.0.0 error with browserify workflow + +### 4.1.0 (Jan 15, 2016) +* added `.ratignore` file +* [CB-10319](https://issues.apache.org/jira/browse/CB-10319) **android** Adding reflective helper methods for permission requests +* [CB-10023](https://issues.apache.org/jira/browse/CB-10023) Fix `proxy not found error` on Chrome. +* [CB-8863](https://issues.apache.org/jira/browse/CB-8863) **ios** Fix block usage of self + +### 4.0.0 (Nov 18, 2015) +* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated `RELEASENOTES` to be newest to oldest +* [CB-8497](https://issues.apache.org/jira/browse/CB-8497) Fix handling of file paths with `#` character +* Do not inject default `AndroidPersistentFileLocation` into `config.xml` +* [CB-9891](https://issues.apache.org/jira/browse/CB-9891): Fix permission errors due to `URI encoding` inconsistency on **Android** +* Fixed `NullPointer Exception` in **Android 5** and above due to invalid column name on cursor +* Fix default persistent file location +* fix `applicationDirectory` to use `ms-appx:///` +* Add **Windows** paths to `cordova.file` object +* [CB-9851](https://issues.apache.org/jira/browse/CB-9851) Document `cdvfile` protocol quirk - using `cdvfile://` in the `DOM` is not supported on **Windows** +* [CB-9752](https://issues.apache.org/jira/browse/CB-9752) `getDirectory` fails on valid directory with assets filesystem +* [CB-7253](https://issues.apache.org/jira/browse/CB-7253) `requestFileSystem` fails when no external storage is present +* Adding permissions for **Marshmallow**. Now supports **Anrdoid 6.0** +* Fixing contribute link. +* always use setters to fix memory issues without `ARC` for **iOS** +* [CB-9331](https://issues.apache.org/jira/browse/CB-9331) `getFreeDiskSpace` **iOS**. +* override `resolveLocalFileSystemURL` by `webkitResolveLocalFileSystemURL` for **browser** platform add `.project` into git ignore list +* Fail with `FileError.ENCODING_ERR` on encoding exception. +* [CB-9544](https://issues.apache.org/jira/browse/CB-9544) Add file plugin for **OSX** +* [CB-9539](https://issues.apache.org/jira/browse/CB-9539) Fixed test failure on **Android** emulator +* Added docs on `CSP` rules needed for using `cdvfile` in DOM src. This closes #120 +* Added `cdvfile` protocol purpose description and examples + +### 3.0.0 (Aug 18, 2015) +* Make Android default persistent file location internal +* Fixed issue with file paths not existing when using browserify +* [CB-9251](https://issues.apache.org/jira/browse/CB-9251): Changed from Intents to Preferences object as per the issue +* [CB-9215](https://issues.apache.org/jira/browse/CB-9215) Add cordova-plugin-file manual test for windows platform + +### 2.1.0 (Jun 17, 2015) +* added missing license header +* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-file documentation translation: cordova-plugin-file +* fix npm md +* [CB-8844](https://issues.apache.org/jira/browse/CB-8844) Increased timeout for asset tests +* Updated resolveFileSystem.js so it can be parsed by uglifyJS +* [CB-8860](https://issues.apache.org/jira/browse/CB-8860) cordova-plugin-file documentation translation: cordova-plugin-file +* [CB-8792](https://issues.apache.org/jira/browse/CB-8792) Fixes reading of json files using readAsText + +### 2.0.0 (Apr 15, 2015) +* [CB-8849](https://issues.apache.org/jira/browse/CB-8849) Fixed ReadAsArrayBuffer to return ArrayBuffer and not Array on WP8 +* [CB-8819](https://issues.apache.org/jira/browse/CB-8819) Fixed FileReader's readAsBinaryString on wp8 +* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) gave plugin major version bump +* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) android: Fix broken unit tests from plugin rename +* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) changed plugin-id to pacakge-name +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) properly updated translated docs to use new id +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id +* Use TRAVIS_BUILD_DIR, install paramedic by npm +* docs: added Windows to supported platforms +* [CB-8699](https://issues.apache.org/jira/browse/CB-8699) [CB-6428](https://issues.apache.org/jira/browse/CB-6428) Fix uncompressed assets being copied as zero length files +* [CB-6428](https://issues.apache.org/jira/browse/CB-6428) android: Fix assets FileEntry having size of -1 +* android: Move URLforFullPath into base class (and rename to localUrlforFullPath) +* [CB-6428](https://issues.apache.org/jira/browse/CB-6428) Mention build-extras.gradle in README +* [CB-7109](https://issues.apache.org/jira/browse/CB-7109) android: Parse arguments off of the main thread (close #97) +* [CB-8695](https://issues.apache.org/jira/browse/CB-8695) ios: Fix `blob.slice()` for `asset-library` URLs (close #105) +* Tweak build-extras.gradle to just read/write to main `assets/` instead of `build/` +* [CB-8689](https://issues.apache.org/jira/browse/CB-8689) Fix NPE in makeEntryForNativeUri (was affecting file-transfer) +* [CB-8675](https://issues.apache.org/jira/browse/CB-8675) Revert "CB-8351 ios: Use base64EncodedStringWithOptions instead of CordovaLib's class extension" +* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) Updated Readme +* [CB-8659](https://issues.apache.org/jira/browse/CB-8659): ios: 4.0.x Compatibility: Remove use of initWebView method +* Add a cache to speed up AssetFilesystem directory listings +* [CB-8663](https://issues.apache.org/jira/browse/CB-8663) android: Don't notify MediaScanner of private files +* Don't log stacktrace for normal exceptions (e.g. file not found) +* android: Don't use LimitedInputStream when reading entire file (optimization) +* [CB-6428](https://issues.apache.org/jira/browse/CB-6428) android: Add support for directory copies from assets -> filesystem +* android: Add `listChildren()`: Java-consumable version of `readEntriesAtLocalURL()` +* [CB-6428](https://issues.apache.org/jira/browse/CB-6428) android: Add support for file:///android_asset URLs +* [CB-8642](https://issues.apache.org/jira/browse/CB-8642) android: Fix content URIs not working with resolve / copy +* Tweak tests to fail if deleteEntry fails (rather than time out) +* android: Ensure LocalFilesystemURL can only be created with "cdvfile" URLs +* android: Move CordovaResourceApi into Filesystem base class +* android: Use `CordovaResourceApi.mapUriToFile()` rather than own custom logic in ContentFilesystem +* android: Use Uri.parse rather than manual parsing in resolveLocalFileSystemURI +* Tweak test case that failed twice on error rather than just once +* android: Delete invalid JavaDoc (lint errors) +* android: Use CordovaResourceApi rather than FileHelper +* [CB-8032](https://issues.apache.org/jira/browse/CB-8032) - File Plugin - Add nativeURL external method support for CDVFileSystem->makeEntryForPath:isDirectory: (closes #96) +* [CB-8567](https://issues.apache.org/jira/browse/CB-8567) Integrate TravisCI +* [CB-8438](https://issues.apache.org/jira/browse/CB-8438) cordova-plugin-file documentation translation: cordova-plugin-file +* [CB-8538](https://issues.apache.org/jira/browse/CB-8538) Added package.json file +* [CB-7956](https://issues.apache.org/jira/browse/CB-7956) Add cordova-plugin-file support for browser platform +* [CB-8423](https://issues.apache.org/jira/browse/CB-8423) Corrected usage of done() in async tests +* [CB-8459](https://issues.apache.org/jira/browse/CB-8459) Fixes spec 111 failure due to incorrect relative paths handling +* Code cleanup, whitespace +* Added nativeURL property to FileEntry, implemented readAsArrayBuffer and readAsBinaryString + +### 1.3.3 (Feb 04, 2015) +* [CB-7927](https://issues.apache.org/jira/browse/CB-7927) Encoding data to bytes instead of chars when writing a file. +* ios: Fix compile warning about implicit int conversion +* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Use base64EncodedStringWithOptions instead of CordovaLib's class extension +* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Use argumentForIndex rather than NSArray extension +* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Use a local copy of valueForKeyIsNumber rather than CordovaLib's version +* windows: Handle url's containing absolute windows path starting with drive letter and colon (encoded as %3A) through root FS +* windows: Rework to use normal url form +* android: refactor: Make Filesystem base class store its own name, rootUri, and rootEntry +* android: Simplify code a bit by making makeEntryForPath not throw JSONException +* [CB-6431](https://issues.apache.org/jira/browse/CB-6431) android: Fix plugin breaking content: URLs +* [CB-7375](https://issues.apache.org/jira/browse/CB-7375) Never create new FileSystem instances (except on windows since they don't implement requestAllFileSystems()) + +### 1.3.2 (Dec 02, 2014) +* Gets rid of thread block error in File plugin +* [CB-7917](https://issues.apache.org/jira/browse/CB-7917) Made tests file.spec.114 - 116 pass for **Windows** platform +* [CB-7977](https://issues.apache.org/jira/browse/CB-7977) Mention `deviceready` in plugin docs +* [CB-7602](https://issues.apache.org/jira/browse/CB-7602): Fix `isCopyOnItself` logic +* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-file documentation translation: cordova-plugin-file +* Use one proxy for both **Windows** and **Windows8** platforms +* [CB-6994](https://issues.apache.org/jira/browse/CB-6994) Fixes result, returned by proxy's write method +* [fxos] update `__format__` to match `pathsPrefix` +* [CB-6994](https://issues.apache.org/jira/browse/CB-6994) Improves merged code to be able to write a File +* Optimize `FileProxy` for **Windows** platforms +* Synchronize changes with **Windows** platform +* Fix function write for big files on **Windows 8** +* Write file in background +* [CB-7487](https://issues.apache.org/jira/browse/CB-7487) **Android** Broadcast file write This allows MTP USB shares to show the file immediately without reboot/manual refresh using 3rd party app. +* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-file documentation translation: cordova-plugin-file +* [CB-7571](https://issues.apache.org/jira/browse/CB-7571) Bump version of nested plugin to match parent plugin + +### 1.3.1 (Sep 17, 2014) +* [CB-7471](https://issues.apache.org/jira/browse/CB-7471) cordova-plugin-file documentation translation +* [CB-7272](https://issues.apache.org/jira/browse/CB-7272) Replace confusing "r/o" abbreviation with just "r" +* [CB-7423](https://issues.apache.org/jira/browse/CB-7423) encode path before attempting to resolve +* [CB-7375](https://issues.apache.org/jira/browse/CB-7375) Fix the filesystem name in resolveLocalFileSystemUri +* [CB-7445](https://issues.apache.org/jira/browse/CB-7445) [BlackBerry10] resolveLocalFileSystemURI - change DEFAULT_SIZE to MAX_SIZE +* [CB-7458](https://issues.apache.org/jira/browse/CB-7458) [BlackBerry10] resolveLocalFileSystemURL - add filesystem property +* [CB-7445](https://issues.apache.org/jira/browse/CB-7445) [BlackBerry10] Add default file system size to prevent quota exceeded error on initial install +* [CB-7431](https://issues.apache.org/jira/browse/CB-7431) Avoid calling done() twice in file.spec.109 test +* [CB-7413](https://issues.apache.org/jira/browse/CB-7413) Adds support of 'ms-appdata://' URIs +* [CB-7422](https://issues.apache.org/jira/browse/CB-7422) [File Tests] Use proper fileSystem to create fullPath +* [CB-7375](https://issues.apache.org/jira/browse/CB-7375) [Entry] get proper filesystem in Entry +* Amazon related changes. +* [CB-7375](https://issues.apache.org/jira/browse/CB-7375) Remove leading slash statement from condition +* Refactored much of the logic in FileMetadata constructor. Directory.size will return 0 +* [CB-7419](https://issues.apache.org/jira/browse/CB-7419) [WP8] Added support to get metada from dir +* [CB-7418](https://issues.apache.org/jira/browse/CB-7418) [DirectoryEntry] Added fullPath variable as part of condition +* [CB-7417](https://issues.apache.org/jira/browse/CB-7417) [File tests] added proper matcher to compare fullPath property +* [CB-7375](https://issues.apache.org/jira/browse/CB-7375) Partial revert to resolve WP8 failures +* Overwrite existing file on getFile when create is true +* [CB-7375](https://issues.apache.org/jira/browse/CB-7375) [CB-6148](https://issues.apache.org/jira/browse/CB-6148): Ensure that return values from copy and move operations reference the correct filesystem +* [CB-6724](https://issues.apache.org/jira/browse/CB-6724) changed style detail on documentation +* Added new js files to amazon-fireos platform. +* Adds Windows platform +* Fixes multiple mobilespec tests errors +* Removed test/tests.js module from main plugin.xml +* [CB-7094](https://issues.apache.org/jira/browse/CB-7094) renamed folder to tests + added nested plugin.xml +* added documentation for manual tests +* [CB-6923](https://issues.apache.org/jira/browse/CB-6923) Adding support to handle relative paths +* Style improvements on Manual tests +* [CB-7094](https://issues.apache.org/jira/browse/CB-7094) Ported File manual tests + +### 1.3.0 (Aug 06, 2014) +* **FFOS** Remove unsupported paths from requestAllPaths +* **FFOS** Support for resolve URI, request all paths and local app directory. +* [CB-4263](https://issues.apache.org/jira/browse/CB-4263) set ready state to done before onload +* [CB-7167](https://issues.apache.org/jira/browse/CB-7167) [BlackBerry10] copyTo - return wrapped entry rather than native +* [CB-7167](https://issues.apache.org/jira/browse/CB-7167) [BlackBerry10] Add directory support to getFileMetadata +* [CB-7167](https://issues.apache.org/jira/browse/CB-7167) [BlackBerry10] Fix tests detection of blob support (window.Blob is BlobConstructor object) +* [CB-7161](https://issues.apache.org/jira/browse/CB-7161) [BlackBerry10] Add file system directory paths +* [CB-7093](https://issues.apache.org/jira/browse/CB-7093) Create separate plugin.xml for new-style tests +* [CB-7057](https://issues.apache.org/jira/browse/CB-7057) Docs update: elaborate on what directories are for +* [CB-7093](https://issues.apache.org/jira/browse/CB-7093): Undo the effects of an old bad S&R command +* [CB-7093](https://issues.apache.org/jira/browse/CB-7093): Remove a bunch of unneeded log messages +* [CB-7093](https://issues.apache.org/jira/browse/CB-7093): Add JS module to plugin.xml file for auto-tests +* [CB-7093](https://issues.apache.org/jira/browse/CB-7093) Ported automated file tests +* **WINDOWS** remove extra function closure, not needed +* **WINDOWS** remove check for undefined fail(), it is defined by the proxy and always exists +* **WINDOWS** re-apply readAsBinaryString and readAsArrayBuffer +* **WINDOWS** Moved similar calls to be the same calls, aliased long namespaced functions +* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Updated translations for docs. +* [CB-6571](https://issues.apache.org/jira/browse/CB-6571) Fix getParentForLocalURL to work correctly with directories with trailing '/' (This closes #58) +* UTTypeCopyPreferredTagWithClass returns nil mimetype for css when there is no network +* updated spec links in docs ( en only ) +* [CB-6571](https://issues.apache.org/jira/browse/CB-6571) add trailing space it is missing in DirectoryEnty constructor. +* [CB-6980](https://issues.apache.org/jira/browse/CB-6980) Fixing filesystem:null property in Entry +* Add win8 support for readAsBinaryString and readAsArrayBuffer +* [FFOS] Update FileProxy.js +* [CB-6940](https://issues.apache.org/jira/browse/CB-6940): Fixing up commit from dzeims +* [CB-6940](https://issues.apache.org/jira/browse/CB-6940): Android: cleanup try/catch exception handling +* [CB-6940](https://issues.apache.org/jira/browse/CB-6940): `context.getExternal*` methods return null if sdcard isn't in mounted state, causing exceptions that prevent startup from reaching readystate +* Fix mis-handling of filesystem reference in Entry.moveTo ('this' used in closure). +* [CB-6902](https://issues.apache.org/jira/browse/CB-6902): Use File.lastModified rather than .lastModifiedDate +* [CB-6922](https://issues.apache.org/jira/browse/CB-6922): Remove unused getMetadata native code +* [CB-6922](https://issues.apache.org/jira/browse/CB-6922): Use getFileMetadata consistently to get metadata +* changed fullPath to self.rootDocsPath +* [CB-6890](https://issues.apache.org/jira/browse/CB-6890): Fix pluginManager access for 4.0.x branch + +### 1.2.1 +* [CB-6922](https://issues.apache.org/jira/browse/CB-6922) Fix inconsistent handling of lastModifiedDate and modificationTime +* [CB-285](https://issues.apache.org/jira/browse/CB-285): Document filesystem root properties + +### 1.2.0 (Jun 05, 2014) +* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Spanish and French Translations added. Github close #31 +* updated this reference to window +* Add missing semicolon (copy & paste error) +* Fix compiler warning about symbol in interface not matching implementation +* Fix sorting order in supported platforms +* ubuntu: increase quota value +* ubuntu: Change FS URL scheme to 'cdvfile' +* ubuntu: Return size with Entry.getMetadata() method +* [CB-6803](https://issues.apache.org/jira/browse/CB-6803) Add license +* Initial implementation for Firefox OS +* Small wording tweaks +* Fixed toURL() toInternalURL() information in the doku +* ios: Don't fail a write of zero-length payload. +* [CB-285](https://issues.apache.org/jira/browse/CB-285) Docs for cordova.file.\*Directory properties +* [CB-285](https://issues.apache.org/jira/browse/CB-285) Add cordova.file.\*Directory properties for iOS & Android +* [CB-3440](https://issues.apache.org/jira/browse/CB-3440) [BlackBerry10] Proxy based implementation +* Fix typo in docs "app-bundle" -> "bundle" +* [CB-6583](https://issues.apache.org/jira/browse/CB-6583) ios: Fix failing to create entry when space in parent path +* [CB-6571](https://issues.apache.org/jira/browse/CB-6571) android: Make DirectoryEntry.toURL() have a trailing / +* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md +* [CB-6525](https://issues.apache.org/jira/browse/CB-6525) android, ios: Allow file: URLs in all APIs. Fixes FileTransfer.download not being called. +* fix the Windows 8 implementation of the getFile method +* Update File.js for typo: lastModifiedData --> lastModifiedDate (closes #38) +* Add error codes. +* [CB-5980](https://issues.apache.org/jira/browse/CB-5980) Updated version and RELEASENOTES.md for release 1.0.0 +* Add NOTICE file +* [CB-6114](https://issues.apache.org/jira/browse/CB-6114) Updated version and RELEASENOTES.md for release 1.0.1 +* [CB-5980](https://issues.apache.org/jira/browse/CB-5980) Updated version and RELEASENOTES.md for release 1.0.0 + +### 1.1.0 (Apr 17, 2014) +* [CB-4965](https://issues.apache.org/jira/browse/CB-4965): Remove tests from file plugin +* Android: Allow file:/ URLs +* [CB-6422](https://issues.apache.org/jira/browse/CB-6422): [windows8] use cordova/exec/proxy +* [CB-6249](https://issues.apache.org/jira/browse/CB-6249): [android] Opportunistically resolve content urls to file +* [CB-6394](https://issues.apache.org/jira/browse/CB-6394): [ios, android] Add extra filesystem roots +* [CB-6394](https://issues.apache.org/jira/browse/CB-6394): [ios, android] Fix file resolution for the device root case +* [CB-6394](https://issues.apache.org/jira/browse/CB-6394): [ios] Return ENCODING_ERR when fs name is not valid +* [CB-6393](https://issues.apache.org/jira/browse/CB-6393): Change behaviour of toURL and toNativeURL +* ios: Style: plugin initialization +* ios: Fix handling of file URLs with encoded spaces +* Always use Android's recommended temp file location for temporary file system +* [CB-6352](https://issues.apache.org/jira/browse/CB-6352): Allow FileSystem objects to be serialized to JSON +* [CB-5959](https://issues.apache.org/jira/browse/CB-5959): size is explicitly 0 if not set, file.spec.46&47 are testing the type of size +* [CB-6242](https://issues.apache.org/jira/browse/CB-6242): [BlackBerry10] Add deprecated version of resolveLocalFileSystemURI +* [CB-6242](https://issues.apache.org/jira/browse/CB-6242): [BlackBerry10] add file:/// prefix for toURI / toURL +* [CB-6242](https://issues.apache.org/jira/browse/CB-6242): [BlackBerry10] Polyfill window.requestAnimationFrame for OS < 10.2 +* [CB-6242](https://issues.apache.org/jira/browse/CB-6242): [BlackBerry10] Override window.resolveLocalFileSystemURL +* [CB-6212](https://issues.apache.org/jira/browse/CB-6212): [iOS] fix warnings compiled under arm64 64-bit +* ios: Don't cache responses from CDVFile's URLProtocol +* [CB-6199](https://issues.apache.org/jira/browse/CB-6199): [iOS] Fix toNativeURL() not escaping characters properly +* [CB-6148](https://issues.apache.org/jira/browse/CB-6148): Fix cross-filesystem copy and move +* fixed setMetadata() to use the formatted fullPath +* corrected typo which leads to a "comma expression" +* [CB-4952](https://issues.apache.org/jira/browse/CB-4952): ios: Resolve symlinks in file:// URLs +* Add docs about the extraFileSystems preference +* [CB-6460](https://issues.apache.org/jira/browse/CB-6460): Update license headers + +### 1.0.1 (Feb 28, 2014) +* [CB-6116](https://issues.apache.org/jira/browse/CB-6116) Fix error where resolveLocalFileSystemURL would fail +* [CB-6106](https://issues.apache.org/jira/browse/CB-6106) Add support for nativeURL attribute on Entry objects +* [CB-6110](https://issues.apache.org/jira/browse/CB-6110) iOS: Fix typo in filesystemPathForURL: method +* Android: Use most specific FS match when resolving file: URIs +* iOS: Update fileSystemURLforLocalPath: to return the most match url. +* Allow third-party plugin registration, and the total count of fs type is not limited to just 4. +* [CB-6097](https://issues.apache.org/jira/browse/CB-6097) Added missing files for amazon-fireos platform. Added onLoad flag to true. +* [CB-6087](https://issues.apache.org/jira/browse/CB-6087) Android, iOS: Load file plugin on startup +* [CB-6013](https://issues.apache.org/jira/browse/CB-6013) BlackBerry10: wrap webkit prefixed called in requestAnimationFrame +* Update plugin writers' documentation +* [CB-6080](https://issues.apache.org/jira/browse/CB-6080) Fix file copy when src and dst are on different local file systems +* [CB-6057](https://issues.apache.org/jira/browse/CB-6057) Add methods for plugins to convert between URLs and paths +* [CB-6050](https://issues.apache.org/jira/browse/CB-6050) Public method for returning a FileEntry from a device file path +* [CB-2432](https://issues.apache.org/jira/browse/CB-2432) [CB-3185](https://issues.apache.org/jira/browse/CB-3185), [CB-5975](https://issues.apache.org/jira/browse/CB-5975): Fix Android handling of content:// URLs +* [CB-6022](https://issues.apache.org/jira/browse/CB-6022) Add upgrade notes to doc +* [CB-5233](https://issues.apache.org/jira/browse/CB-5233) Make asset-library urls work properly on iOS +* [CB-6012](https://issues.apache.org/jira/browse/CB-6012) Preserve query strings on cdvfile:// URLs where necessary +* [CB-6010](https://issues.apache.org/jira/browse/CB-6010) Test properly for presence of URLforFilesystemPath method +* [CB-5959](https://issues.apache.org/jira/browse/CB-5959) Entry.getMetadata should return size attribute + +### 1.0.0 (Feb 05, 2014) +* [CB-5974](https://issues.apache.org/jira/browse/CB-5974): Use safe 'Compatibilty' mode by default +* [CB-5915](https://issues.apache.org/jira/browse/CB-5915): [CB-5916](https://issues.apache.org/jira/browse/CB-5916): Reorganize preference code to make defaults possible +* [CB-5974](https://issues.apache.org/jira/browse/CB-5974): Android: Don't allow File operations to continue when not configured +* [CB-5960](https://issues.apache.org/jira/browse/CB-5960): ios: android: Properly handle parent references in getFile/getDirectory +* [ubuntu] adopt to recent changes +* Add default FS root to new FS objects +* [CB-5899](https://issues.apache.org/jira/browse/CB-5899): Make DirectoryReader.readEntries return properly formatted Entry objects +* Add constuctor params to FileUploadResult related to [CB-2421](https://issues.apache.org/jira/browse/CB-2421) +* Fill out filesystem attribute of entities returned from resolveLocalFileSystemURL +* [CB-5916](https://issues.apache.org/jira/browse/CB-5916): Create documents directories if they don't exist +* [CB-5915](https://issues.apache.org/jira/browse/CB-5915): Create documents directories if they don't exist +* [CB-5916](https://issues.apache.org/jira/browse/CB-5916): Android: Fix unfortunate NPE in config check +* [CB-5916](https://issues.apache.org/jira/browse/CB-5916): Android: Add "/files/" to persistent files path +* [CB-5915](https://issues.apache.org/jira/browse/CB-5915): ios: Update config preference (and docs) to match issue +* [CB-5916](https://issues.apache.org/jira/browse/CB-5916): Android: Add config preference for Android persistent storage location +* iOS: Add config preference for iOS persistent storage location +* iOS: Android: Allow third-party plugin registration +* Android: Expose filePlugin getter so that other plugins can register filesystems +* Fix typos in deprecation message +* Add backwards-compatibility shim for file-transfer +* Android: Allow third-party plugin registration +* [CB-5810](https://issues.apache.org/jira/browse/CB-5810) [BlackBerry10] resolve local:/// paths (application assets) +* [CB-5774](https://issues.apache.org/jira/browse/CB-5774): create DirectoryEntry instead of FileEntry +* Initial fix for [CB-5747](https://issues.apache.org/jira/browse/CB-5747) +* Change default FS URL scheme to "cdvfile" +* Android: Properly format content urls +* Android, iOS: Replace "filesystem" protocol string with constant +* Android: Allow absolute paths on Entry.getFile / Entry.getDirectory +* Android: Make clear that getFile takes a path, not just a filename +* [CB-5008](https://issues.apache.org/jira/browse/CB-5008): Rename resolveLocalFileSystemURI to resolveLocalFileSystemURL; deprecate original +* Remove old file reference from plugin.xml +* Android: Refactor File API +* [CB-4899](https://issues.apache.org/jira/browse/CB-4899) [BlackBerry10] Fix resolve directories +* [CB-5602](https://issues.apache.org/jira/browse/CB-5602) Windows8. Fix File Api mobile spec tests +* Android: Better support for content urls and cross-filesystem copy/move ops +* [CB-5699](https://issues.apache.org/jira/browse/CB-5699) [BlackBerry10] Update resolveLocalFileSystemURI implementation +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Update license comment formatting of doc/index.md +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Add doc.index.md for File plugin. +* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Delete stale snapshot of plugin docs +* [CB-5403](https://issues.apache.org/jira/browse/CB-5403): Backwards-compatibility with file:// urls where possible +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Fixes for ContentFilesystem +* Android: Add method for testing backwards-compatibility of filetransfer plugin +* iOS: Add method for testing backwards-compatiblity of filetransfer plugin +* Android: Updates to allow FileTransfer to continue to work +* Android: Clean up unclosed file objects +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Cleanup +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Add new Android source files to plugin.xml +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Move read, write and truncate methods into modules +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Move copy/move methods into FS modules +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Move getParent into FS modules +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Move getmetadata methods into FS modules +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Move readdir methods into FS modules +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Move remove methods into FS modules +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Move getFile into FS modules +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Start refactoring android code: Modular filesystems, rfs, rlfsurl +* [CB-5407](https://issues.apache.org/jira/browse/CB-5407): Update android JS to use FS urls +* [CB-5405](https://issues.apache.org/jira/browse/CB-5405): Use URL formatting for Entry.toURL +* [CB-5532](https://issues.apache.org/jira/browse/CB-5532) Fix +* Log file path for File exceptions. +* Partial fix for iOS File compatibility with previous fileTransfer plugin +* [CB-5532](https://issues.apache.org/jira/browse/CB-5532) WP8. Add binary data support to FileWriter +* [CB-5531](https://issues.apache.org/jira/browse/CB-5531) WP8. File Api readAsText incorrectly handles position args +* Added ubuntu platform support +* Added amazon-fireos platform support +* [CB-5118](https://issues.apache.org/jira/browse/CB-5118) [BlackBerry10] Add check for undefined error handler +* [CB-5406](https://issues.apache.org/jira/browse/CB-5406): Extend public API for dependent plugins +* [CB-5403](https://issues.apache.org/jira/browse/CB-5403): Bump File plugin major version +* [CB-5406](https://issues.apache.org/jira/browse/CB-5406): Split iOS file plugin into modules +* [CB-5406](https://issues.apache.org/jira/browse/CB-5406): Factor out filesystem providers in iOS +* [CB-5408](https://issues.apache.org/jira/browse/CB-5408): Add handler for filesystem:// urls +* [CB-5406](https://issues.apache.org/jira/browse/CB-5406): Update iOS native code to use filesystem URLs internally +* [CB-5405](https://issues.apache.org/jira/browse/CB-5405): Update JS code to use URLs exclusively +* [CB-4816](https://issues.apache.org/jira/browse/CB-4816) Fix file creation outside sandbox for BB10 + +### 0.2.5 (Oct 28, 2013) +* [CB-5129](https://issues.apache.org/jira/browse/CB-5129): Add a consistent filesystem attribute to FileEntry and DirectoryEntry objects +* [CB-5128](https://issues.apache.org/jira/browse/CB-5128): added repo + issue tag to plugin.xml for file plugin +* [CB-5015](https://issues.apache.org/jira/browse/CB-5015) [BlackBerry10] Add missing dependency for File.slice +* [CB-5010](https://issues.apache.org/jira/browse/CB-5010) Incremented plugin version on dev branch. + +### 0.2.4 (Oct 9, 2013) +* [CB-5020](https://issues.apache.org/jira/browse/CB-5020) - File plugin should execute on a separate thread +* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Incremented plugin version on dev branch. +* [CB-4504](https://issues.apache.org/jira/browse/CB-4504): Updating FileUtils.java to compensate for Java porting failures in the Android SDK. This fails because Java knows nothing about android_asset not being an actual filesystem + +### 0.2.3 (Sept 25, 2013) +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) bumping&resetting version +* [CB-4903](https://issues.apache.org/jira/browse/CB-4903) File Plugin not loading Windows8 +* [CB-4903](https://issues.apache.org/jira/browse/CB-4903) File Plugin not loading Windows8 +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) renaming references +* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) renaming org.apache.cordova.core.file to org.apache.cordova.file +* Rename CHANGELOG.md -> RELEASENOTES.md +* [CB-4771](https://issues.apache.org/jira/browse/CB-4771) Expose TEMPORARY and PERSISTENT constants on window. +* Fix compiler/lint warnings +* [CB-4764](https://issues.apache.org/jira/browse/CB-4764) Move DirectoryManager.java into file plugin +* [CB-4763](https://issues.apache.org/jira/browse/CB-4763) Copy FileHelper.java into the plugin. +* [CB-2901](https://issues.apache.org/jira/browse/CB-2901) [BlackBerry10] Automatically unsandbox filesystem if path is not in app sandbox +* [CB-4752](https://issues.apache.org/jira/browse/CB-4752) Incremented plugin version on dev branch. + +### 0.2.1 (Sept 5, 2013) +* [CB-4656](https://issues.apache.org/jira/browse/CB-4656) Don't add newlines in data urls within readAsDataUrl. +* [CB-4514](https://issues.apache.org/jira/browse/CB-4514) Making DirectoryCopy Recursive +* [iOS] Simplify the code in resolveLocalFileSystemURI diff --git a/mobile/plugins/cordova-plugin-file/doc/de/README.md b/mobile/plugins/cordova-plugin-file/doc/de/README.md new file mode 100644 index 0000000..242a2f7 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/de/README.md @@ -0,0 +1,335 @@ + + +# cordova-plugin-file + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg)](https://travis-ci.org/apache/cordova-plugin-file) + +Dieses Plugin implementiert eine File-API, die Lese-/Schreibzugriff Zugriff auf Dateien, die auf dem Gerät befinden. + +Dieses Plugin basiert auf mehrere Angaben, einschließlich: die HTML5-File-API + +Die (heute nicht mehr existierenden) Verzeichnisse und System neuesten Erweiterungen: , obwohl die meisten von den Plugin-Code wurde geschrieben, als eine frühere Spec aktuell waren: + +Es implementiert auch die FileWriter Spec: + +Verwendung finden Sie in HTML5 Rocks ausgezeichnete [Dateisystem Artikel.](http://www.html5rocks.com/en/tutorials/file/filesystem/) + +Finden Sie einen Überblick über andere Speicheroptionen Cordovas [Speicher-Führer](http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html). + +Dieses Plugin wird global `cordova.file`-Objekt definiert. + +Obwohl im globalen Gültigkeitsbereich, steht es nicht bis nach dem `deviceready`-Ereignis. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## Installation + + cordova plugin add cordova-plugin-file + + +## Unterstützte Plattformen + + * Amazon Fire OS + * Android + * BlackBerry 10 + * Firefox OS + * iOS + * Windows Phone 7 und 8 * + * Windows 8 * + * Windows* + * Browser + +\* *These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`.* + +## Wo Dateien gespeichert + +Stand: V1 werden URLs auf wichtige Datei-System-Verzeichnisse zur Verfügung gestellt. Jede URL in der Form *file:///path/to/spot/* ist, und ein `DirectoryEntry` mit `window.resolveLocalFileSystemURL()` konvertiert werden können. + + * `cordova.file.applicationDirectory`-Die schreibgeschützten Verzeichnis, in dem die Anwendung installiert ist. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.applicationStorageDirectory`-Root-Verzeichnis der Anwendungs-Sandbox; auf iOS ist schreibgeschützt (aber bestimmte Unterverzeichnisse [wie `/Documents` ] sind Lese-und Schreibzugriff). Alle enthaltene Daten ist für die app privat. ( *iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.dataDirectory`-Beständige und private Datenspeicherung innerhalb der Anwendungs-Sandbox, die mit internen Speicher (auf Android, externen Speicher verwenden, verwenden Sie `.externalDataDirectory` ). Auf iOS, ist dieses Verzeichnis nicht mit iCloud synchronisiert (verwenden Sie `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.cacheDirectory`-Verzeichnis der zwischengespeicherten Daten-Dateien oder Dateien, die Ihre app einfach neu erstellen können. Das Betriebssystem kann diese Dateien löschen, wenn das Gerät auf Speicher knapp wird, dennoch sollten die apps vom Betriebssystem zum Löschen von Dateien hier nicht verlassen. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.externalApplicationStorageDirectory`-Anwendungsraum auf externen Speicher. (*Android*) + + * `cordova.file.externalDataDirectory`-Wo, app-spezifische Datendateien auf externen Speicher setzen. (*Android*) + + * `cordova.file.externalCacheDirectory`-Anwendungscache auf externen Speicher. (*Android*) + + * `cordova.file.externalRootDirectory`-Externer Speicher (SD-Karte) Stamm. (*Android*, *BlackBerry 10*) + + * `cordova.file.tempDirectory`-Temp-Verzeichnis, dem das OS auf deaktivieren können wird. Verlassen Sie sich nicht auf das Betriebssystem, um dieses Verzeichnis zu löschen; Ihre Anwendung sollte immer Dateien gegebenenfalls entfernen. (*iOS*) + + * `cordova.file.syncedDataDirectory`-Hält app-spezifische Dateien, die (z. B. auf iCloud) synchronisiert werden sollten. (*iOS*) + + * `cordova.file.documentsDirectory`-Dateien für die app, aber privat sind sinnvoll, andere Anwendungen (z.B. Office-Dateien). (*iOS*) + + * `cordova.file.sharedDirectory`-Dateien für alle Anwendungen (*BlackBerry 10* weltweit verfügbar) + +## Dateisystemlayouts + +Obwohl technisch ein Implementierungsdetail, kann es sehr hilfreich zu wissen, wie die `cordova.file.*`-Eigenschaften physikalische Pfade auf einem echten Gerät zugeordnet sein. + +### iOS-Datei-System-Layout + +| Gerätepfad | `Cordova.file.*` | `iosExtraFileSystems` | R/w? | persistent? | OS löscht | Sync | Private | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:----:|:-----------:|:------------:|:----:|:-------:| +| `/ Var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N/A | N/A | N/A | Ja | +|    `appname.app/` | applicationDirectory | Bundle | r | N/A | N/A | N/A | Ja | +|       `www/` | - | - | r | N/A | N/A | N/A | Ja | +|    `Documents/` | documentsDirectory | Dokumente | R/w | Ja | Nein | Ja | Ja | +|       `NoCloud/` | - | Dokumente-nosync | R/w | Ja | Nein | Nein | Ja | +|    `Library` | - | Bibliothek | R/w | Ja | Nein | Ja? | Ja | +|       `NoCloud/` | dataDirectory | Bibliothek-nosync | R/w | Ja | Nein | Nein | Ja | +|       `Cloud/` | syncedDataDirectory | - | R/w | Ja | Nein | Ja | Ja | +|       `Caches/` | cacheDirectory | Cache | R/w | Ja * | Ja**\* | Nein | Ja | +|    `tmp/` | tempDirectory | - | R/w | Nein** | Ja**\* | Nein | Ja | + +\ * Dateien über app-Neustarts und Upgrades beibehalten, aber dieses Verzeichnis kann gelöscht werden, wenn das OS begehrt. Ihre Anwendung sollte in der Lage, alle Inhalte neu zu erstellen, die gelöscht werden können. + +** -Dateien kann über app-Neustarts beizubehalten, aber verlasse dich nicht auf dieses Verhalten. Dateien sind nicht unbedingt Aktuelles beibehalten. Ihre Anwendung sollte Dateien aus diesem Verzeichnis entfernen, wenn es gilt, diese Dateien werden entfernt, da das OS nicht wann (oder auch wenn) garantiert. + +**\ * The OS kann den Inhalt dieses Verzeichnisses löschen, wann immer es sich anfühlt, ist es erforderlich, aber verlassen Sie sich nicht dazu. Sie sollten dieses Verzeichnis entsprechend Ihrer Anwendung deaktivieren. + +### Android File System-Layout + +| Gerätepfad | `Cordova.file.*` | `AndroidExtraFileSystems` | R/w? | persistent? | OS löscht | Private | +|:------------------------------------------------ |:----------------------------------- |:------------------------- |:----:|:-----------:|:----------:|:-------:| +| `file:///android_asset/` | applicationDirectory | | r | N/A | N/A | Ja | +| `/ Data/Data/< app-Id > /` | applicationStorageDirectory | - | R/w | N/A | N/A | Ja | +|    `cache` | cacheDirectory | Cache | R/w | Ja | Ja\* | Ja | +|    `files` | dataDirectory | Dateien | R/w | Ja | Nein | Ja | +|       `Documents` | | Dokumente | R/w | Ja | Nein | Ja | +| `< Sdcard > /` | externalRootDirectory | sdcard | R/w | Ja | Nein | Nein | +|    `Android/data//` | externalApplicationStorageDirectory | - | R/w | Ja | Nein | Nein | +|       `cache` | externalCacheDirectry | Cache-extern | R/w | Ja | Nein** | Nein | +|       `files` | externalDataDirectory | Dateien-extern | R/w | Ja | Nein | Nein | + +\ * OS kann regelmäßig dieses Verzeichnis zu löschen, aber verlasse dich nicht auf dieses Verhalten. Deaktivieren Sie den Inhalt dieses Verzeichnisses für Ihre Anwendung geeigneten. Ein Benutzer den Cache manuell löschen sollte, werden die Inhalte dieses Verzeichnisses entfernt. + +** Der OS nicht klar dieses Verzeichnis automatisch; Sie sind verantwortlich für die Inhalte selbst verwalten. Der Benutzer den Cache manuell löschen sollte, werden der Inhalt des Verzeichnisses entfernt. + +**Hinweis**: Wenn externe Speichergeräte nicht bereitgestellt werden kann, sind die `cordova.file.external*` Eigenschaften `null`. + +### BlackBerry 10-File-System-Layout + +| Gerätepfad | `Cordova.file.*` | R/w? | persistent? | OS löscht | Private | +|:----------------------------------------------------------- |:--------------------------- |:----:|:-----------:|:---------:|:-------:| +| `file:///Accounts/1000/APPDATA/ < app Id > /` | applicationStorageDirectory | r | N/A | N/A | Ja | +|    `app/native` | applicationDirectory | r | N/A | N/A | Ja | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | R/w | Nein | Ja | Ja | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | R/w | Ja | Nein | Ja | +| `file:///Accounts/1000/Removable/sdcard` | externalRemovableDirectory | R/w | Ja | Nein | Nein | +| `file:///Accounts/1000/Shared` | sharedDirectory | R/w | Ja | Nein | Nein | + +*Hinweis*: Wenn die Anwendung bereitgestellt wird, um Perimeter zu arbeiten, alle Pfade sind relativ /accounts/1000-enterprise. + +## Android Eigenarten + +### Android permanenten Speicherort + +Es gibt mehrere gültige Speicherorte, persistente Dateien auf einem Android-Gerät zu speichern. Finden Sie auf [dieser Seite](http://developer.android.com/guide/topics/data/data-storage.html) eine ausführliche Diskussion über die verschiedenen Möglichkeiten. + +Frühere Versionen des Plugins wählen würde, den Speicherort der temporären und permanenten Dateien beim Start, basierend auf, ob das Gerät behauptete, dass die SD-Karte (oder gleichwertige Speicherpartition) bereitgestellt wurde. Wenn die SD-Karte eingelegt wurde, oder wenn eine große interne Speicherpartition verfügbar war (wie auf Nexus-Geräten) und dann in die Wurzel dieses Raumes, die persistenten Dateien gespeichert werden. Dies bedeutete, dass alle Cordova apps aller verfügbaren Dateien auf der Karte sehen konnte. + +Wenn die SD-Karte nicht verfügbar war, dann Vorgängerversionen Daten unter speichern würde `/data/data/`, die isoliert Anwendungen voneinander, aber möglicherweise noch Ursache Daten zwischen Benutzern freigegeben werden. + +Es ist jetzt möglich, ob Sie Dateien der internen Datei-Speicherort oder unter Verwendung der bisherigen Logik, mit einer Präferenz in der Anwendung-`config.xml`-Datei speichern möchten. Hierzu fügen Sie eine dieser zwei Zeilen zu `"config.xml"`: + + + + + + +Ohne diese Zeile wird das Datei Plugin `Compatibility` als Standard verwenden. Wenn ein Präferenz-Tag vorhanden ist, und nicht einen der folgenden Werte, wird die Anwendung nicht gestartet. + +Wenn Ihre Anwendung für Benutzer zuvor versandt wird, mithilfe eines älteren (Pre-1.0) Version dieses Plugins und gespeicherte Dateien im permanenten Dateisystem hat, dann sollten Sie die Einstellung zur `Compatibility` einstellen. Wechseln die Location auf "Internal" würde bedeuten, dass Benutzer, die aktualisieren Sie ihre Anwendung, möglicherweise nicht auf ihre zuvor gespeicherte Dateien, abhängig von ihrem Gerät zugreifen. + +Wenn Ihre Anwendung neu ist, oder nie zuvor Dateien im Dateisystem persistent gespeichert hat, wird die `Internal` Einstellung in der Regel empfohlen. + +### Langsame rekursive Operationen für /android_asset + +Auflisten von Verzeichnissen Vermögenswert ist wirklich langsam auf Android. Sie können beschleunigen, es oben aber durch `src/android/build-extras.gradle` in das Stammverzeichnis von Ihrem android Projekt hinzufügen (erfordert auch cordova-android@4.0.0 oder größer). + +## iOS Macken + + * `cordova.file.applicationStorageDirectory`ist schreibgeschützt; zum Speichern von Dateien im Stammverzeichnis der Versuch schlägt fehl. Verwenden Sie eine der anderen `cordova.file.*` für iOS definierten Eigenschaften (nur `applicationDirectory` und `applicationStorageDirectory` sind schreibgeschützt). + * `FileReader.readAsText(blob, encoding)` + * Die `encoding` Parameter wird nicht unterstützt und UTF-8-Kodierung ist immer wirksam. + +### iOS permanenten Speicherort + +Es gibt zwei gültige Speicherorte persistente Dateien auf ein iOS-Gerät speichern: das Dokumenten-Verzeichnis und das Verzeichnis Library. Frühere Versionen des Plugins gespeichert immer nur persistente Dateien im Verzeichnis Dokumente. Dies hatte den Nebeneffekt einer Anwendung Dateien in iTunes, die oft unbeabsichtigte, speziell für Anwendungen, die viele kleine Dateien behandeln war, sichtbar zu machen, anstatt komplette Dokumente für den Export, die den beabsichtigten Zweck des Verzeichnisses ist zu produzieren. + +Es ist jetzt möglich, ob Sie Dateien in Dokumente oder Verzeichnis Library mit einer Präferenz in der Anwendung-`config.xml`-Datei speichern möchten. Hierzu fügen Sie eine dieser zwei Zeilen zu `"config.xml"`: + + + + + + +Ohne diese Zeile wird das Datei Plugin `Compatibility` als Standard verwenden. Wenn ein Präferenz-Tag vorhanden ist, und nicht einen der folgenden Werte, wird die Anwendung nicht gestartet. + +Wenn Ihre Anwendung für Benutzer zuvor versandt wird, mithilfe eines älteren (Pre-1.0) Version dieses Plugins und gespeicherte Dateien im permanenten Dateisystem hat, dann sollten Sie die Einstellung zur `Compatibility` einstellen. Standort zur `Library` wechseln würde bedeuten, dass Benutzer, die ihre Anwendung aktualisieren nicht in der Lage wäre, ihre zuvor gespeicherte Dateien zugreifen. + +Wenn die Anwendung neu, oder nie zuvor Dateien im Dateisystem persistent gespeichert hat, wird die Einstellung der `Library` allgemein empfohlen. + +## Firefox OS Macken + +Der Datei-System-API wird von Firefox-OS nicht nativ unterstützt und wird als ein Shim auf IndexedDB implementiert. + + * Schlägt nicht fehl, wenn Sie nicht leere Verzeichnisse entfernen + * Metadaten wird für Verzeichnisse nicht unterstützt. + * Methoden `copyTo` und `moveTo` unterstützen keine Verzeichnisse + +Die folgenden Datenpfade werden unterstützt: * `applicationDirectory` - `xhr` verwendet, um lokale Dateien erhalten, die mit der app verpackt sind. *`dataDirectory` - für persistente app-spezifische Daten-Dateien. *`cacheDirectory` - Cache-Dateien, die app startet überleben sollte (Apps sollten nicht vom Betriebssystem zum Löschen von Dateien hier verlassen). + +## Browser-Eigenheiten + +### Gemeinsamen Macken und Bemerkungen + + * Jeder Browser verwendet ein eigene Sandbox Dateisystem. IE und Firefox verwenden IndexedDB als Basis. Alle Browser verwenden Schrägstrich als Verzeichnistrennzeichen in einem Pfad. + * Directory-Einträge müssen nacheinander erstellt werden. Z. B. der Aufruf `fs.root.getDirectory ("dir1/Ordner2 ', {create:true}, SuccessCallback, ErrorCallback)` schlägt fehl, wenn dir1 nicht existierte. + * Das Plugin fordert Benutzer die Berechtigung zum permanenten Speicher beim ersten Start Anwendung verwenden. + * Plugin unterstützt `Cdvfile://localhost` (lokale Ressourcen) nur. D.h. externe Ressourcen nicht über `Cdvfile` unterstützt. + * Das Plugin folgt nicht ["File System API 8.3 Naming Einschränkungen"](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions). + * BLOB und Datei "`close`-Funktion wird nicht unterstützt. + * `FileSaver` und `BlobBuilder` werden von diesem Plugin nicht unterstützt und müssen nicht geboren. + * Das Plugin unterstützt keine `RequestAllFileSystems`. Diese Funktion fehlt auch in den Spezifikationen. + * Einträge im Verzeichnis werden nicht entfernt werden, wenn Sie verwenden `create: true` Flag für vorhandenes Verzeichnis. + * Über Konstruktor erstellte Dateien werden nicht unterstützt. Sie sollten stattdessen die entry.file-Methode verwenden. + * Jeder Browser verwendet eine eigene Form für Blob-URL-Verweise. + * `readAsDataURL`-Funktion wird unterstützt, aber die Mediatype in Chrom hängt von der Eintrag Namenerweiterung, Mediatype im IE immer leer ist (das ist dasselbe wie `Text-Plain` gemäß der Spezifikation), Mediatype in Firefox ist immer `Application/Octet-Stream`. Beispielsweise, wenn der Inhalt `Abcdefg` gibt dann Firefox `Daten: Anwendung / Octet-Stream; base64, YWJjZGVmZw ==`, IE gibt `Daten:; base64, YWJjZGVmZw ==`, Chrom gibt `Daten: < Mediatype je nach Erweiterung des Eintragsnamens >; base64, YWJjZGVmZw ==`. + * `ToInternalURL` gibt den Pfad zurück, in der Form `file:///persistent/path/to/entry` (Firefox, IE). Chrom gibt den Pfad zurück, in der Form `cdvfile://localhost/persistent/file`. + +### Chrom-Macken + + * Chrom-Dateisystem ist nicht sofort nach Gerät bereit. Als Workaround können Sie `FilePluginIsReady`-Ereignis abonnieren. Beispiel: + +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` + +`Window.isFilePluginReadyRaised`-Funktion können Sie überprüfen, ob Ereignis bereits ausgelöst wurde. -window.requestFileSystem temporär und PERSISTENTE Dateisystem-Quoten sind nicht begrenzt, in Chrom. -Um die dauerhafte Speicherung in Chrom zu erhöhen benötigen Sie `window.initPersistentFileSystem`-Methode aufrufen. Permanenter Speicherkontingent beträgt 5 MB standardmäßig. -Chrome erforderlich `--erlauben-Datei-Zugriff-aus-Files` Argument an den Support API via `file:///` Protokoll führen. -`Datei`-Objekt wird nicht geändert werden, wenn Sie Flag verwenden `{create:true}` als einen vorhandenen `Eintrag` zu erhalten. -Veranstaltungen `cancelable`-Eigenschaft festgelegt ist in Chrom wahr. Dies widerspricht der [Spezifikation](http://dev.w3.org/2009/dap/file-system/file-writer.html). -`toURL`-Funktion in Chrome zurück `Dateisystem:`-Pfad je nach Anwendungshost vorangestellt. Z. B. `filesystem:file:///persistent/somefile.txt`, `Filesystem:http://localhost:8080/persistent/somefile.txt`. -`toURL` Funktionsergebnis enthält keine nachgestellten Schrägstrich bei Verzeichniseintrag. Chrom löst Verzeichnisse mit Schrägstrich-gezogene Urls aber korrekt. -`ResolveLocalFileSystemURL`-Methode erfordert die eingehenden `Url` `Dateisystem` Präfix haben. Beispielsweise sollte die `Url`-Parameter für `ResolveLocalFileSystemURL` in der Form `filesystem:file:///persistent/somefile.txt` im Gegensatz zu der Form `file:///persistent/somefile.txt` in Android. -Veraltete `ToNativeURL`-Funktion wird nicht unterstützt und muss keinen Stub. -`SetMetadata`-Funktion ist nicht in den Spezifikationen angegeben und nicht unterstützt. -INVALID_MODIFICATION_ERR (Code: 9) wird ausgelöst, statt SYNTAX_ERR(code: 8) auf anfordern des Dateisystems nicht existent. -INVALID_MODIFICATION_ERR (Code: 9) wird ausgelöst, anstatt PATH_EXISTS_ERR(code: 12) zu versuchen, die ausschließlich eine Datei oder ein Verzeichnis zu erstellen, die bereits vorhanden ist. -INVALID_MODIFICATION_ERR (Code: 9) wird ausgelöst, anstatt NO_MODIFICATION_ALLOWED_ERR(code: 6) zu versuchen, rufen Sie RemoveRecursively auf das Root-Dateisystem. -INVALID_MODIFICATION_ERR (Code: 9) wird ausgelöst, anstatt NOT_FOUND_ERR(code: 1) zu versuchen, MoveTo-Verzeichnis, das nicht vorhanden ist. + +### Auf der Grundlage von IndexedDB Impl Macken (Firefox und IE) + + * `.` und `.` werden nicht unterstützt. + * IE unterstützt keine `file:///`-Modus; nur der Modus für gehostete ist unterstützten (Http://localhost:xxxx). + * Firefox Dateisystem Größe ist nicht begrenzt, aber jede 50MB-Erweiterung wird eine Benutzer die Berechtigung anzufordern. IE10 können bis zu 10mb kombinierte AppCache und IndexedDB in Implementierung des Dateisystems verwendet, ohne Aufforderung, sobald Sie dieses Niveau, werden, das Sie aufgefordert werden schlagen, wenn Sie es bis Max 250 mb pro Standort erhöht werden sollen. `Size`-Parameter für `RequestFileSystem` Funktion wirkt also nicht Dateisystem in Firefox und IE. + * `ReadAsBinaryString` Funktion heißt es nicht in die Angaben und in IE nicht unterstützt und muss keinen Stub. + * `file.Type` ist immer null. + * Sie sollten nicht erstellen Eintrag mit DirectoryEntry Instanz Rückrufergebnis, die gelöscht wurde. Andernfalls erhalten Sie einen "hängende Eintrag". + * Bevor Sie eine Datei lesen können, die gerade geschrieben wurde, müssen Sie eine neue Instanz dieser Datei erhalten. + * `SetMetadata`-Funktion, die nicht in den Specs genannt unterstützt Feldänderung nur `ModificationTime`. + * `CopyTo` und `MoveTo`-Funktionen unterstützen keine Verzeichnisse. + * Verzeichnisse-Metadaten werden nicht unterstützt. + * Beide Entry.remove und directoryEntry.removeRecursively nicht scheitern, wenn nicht leere Verzeichnisse entfernen - Verzeichnisse entfernt werden stattdessen zusammen mit Inhalt gereinigt. + * `abort` und `truncate`-Funktionen werden nicht unterstützt. + * Progress-Ereignisse werden nicht ausgelöst. Beispielsweise wird dieser Handler nicht ausgeführt werden: + +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## Upgrade Notes + +In v1.0.0 dieses Plugins haben die `FileEntry` und `DirectoryEntry` Strukturen geändert, um mehr im Einklang mit der veröffentlichten Spezifikation sein. + +Vorgängerversionen (Pre-1.0.0) des Plugins den Gerät-Absolute-Dateispeicherort in der Eigenschaft `fullPath` `Entry` Objekte gespeichert. Diese Pfade würde in der Regel aussehen + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Diese Pfade wurden auch von der `toURL()`-Methode der `Entry` Objekte zurückgegeben. + +Mit v1.0.0 ist das `fullPath`-Attribut den Pfad zu der Datei, *relativ zum Stammverzeichnis des Dateisystems HTML*. Also, würde die oben genannten Wege jetzt beide durch ein `FileEntry`-Objekt mit einem `fullPath` von dargestellt werden + + /path/to/file + + +Wenn Ihre Anwendung mit absoluter Gerätepfade arbeitet und Sie zuvor diese Pfade durch die Eigenschaft `fullPath` `Entry` Objekte abgerufen, sollten dann Sie den Code, um stattdessen `entry.toURL()` verwenden aktualisieren. + +Für rückwärts Kompatibilität, die `resolveLocalFileSystemURL()`-Methode wird einen Absolute-Gerätepfad zu akzeptieren und kehrt ein `Entry`-Objekt entspricht, solange diese Datei in den `TEMPORARY` oder `PERSISTENT` Dateisysteme existiert. + +Dies wurde vor allem ein Problem mit dem File-Transfer-Plugin, die zuvor-Absolute-Gerätepfade verwendet (und kann damit noch einverstanden). Es wurde überarbeitet, um mit Dateisystem-URLs korrekt zu arbeiten, damit ersetzen `entry.fullPath` mit `entry.toURL()` immer das Plugin zum Arbeiten mit Dateien auf dem Gerät Probleme lösen sollte. + +In v1.1.0 wurde der Rückgabewert von `toURL()` (siehe \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) geändert, um eine absolute "file://" URL zurückgeben. wo immer möglich. Sicherstellung einer ' Cdvfile:'-URL können Sie an `toInternalURL()`. Diese Methode gibt jetzt Dateisystem URLs der Form zurück. + + cdvfile://localhost/persistent/path/to/file + + +die benutzt werden können, um die Datei eindeutig zu identifizieren. + +## Liste der Fehlercodes und Bedeutungen + +Wenn ein Fehler ausgelöst wird, wird eines der folgenden Codes verwendet werden. + +| Code | Konstante | +| ----:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Konfigurieren das Plugin (Optional) + +Die Menge der verfügbaren Dateisysteme kann pro Plattform konfiguriert sein. Erkennen von iOS und Android ein Tag in `"config.xml"` die Namen der Dateisysteme installiert werden. Standardmäßig sind alle Datei-System-Roots aktiviert. + + + + + +### Android + + * `files`: interne Datei-Speicher-Verzeichnis der Anwendung + * `files-external`: Verzeichnis der Anwendung externe Datei Speicher + * `sdcard`: das externe Globaldatei-Speicherverzeichnis (Dies ist die Wurzel der SD-Karte, sofern installiert). Sie benötigen die Berechtigung zur Verwendung dieses `android.permission.WRITE_EXTERNAL_STORAGE`. + * `cache`: internen Cache-Verzeichnis der Anwendung + * `cache-external`: externer Cache-Verzeichnis der Anwendung + * `root`: das gesamte Gerät-Dateisystem + +Android unterstützt auch eine spezielle Dateisystem mit dem Namen "documents", die ein Unterverzeichnis "/Documents/" die "files" Dateisystem darstellt. + +### iOS + + * `library`: Bibliothek-Verzeichnis der Anwendung + * `documents`: Dokumente-Verzeichnis der Anwendung + * `cache`: Cache-Verzeichnis der Anwendung + * `bundle`: die Anwendung Bündel; den Speicherort der die app selbst auf dem Datenträger (schreibgeschützt) + * `root`: das gesamte Gerät-Dateisystem + +Standardmäßig können die Bibliothek und Dokumenten-Verzeichnisse mit iCloud synchronisiert werden. Sie können auch verlangen, zwei zusätzliche Dateisysteme, `library-nosync` und `documents-nosync`, die einem speziellen nicht synchronisierten Verzeichnis innerhalb darstellen der `/Library` oder `/Documents`-Dateisystem. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/de/index.md b/mobile/plugins/cordova-plugin-file/doc/de/index.md new file mode 100644 index 0000000..2a51695 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/de/index.md @@ -0,0 +1,338 @@ + + +# cordova-plugin-file + +Dieses Plugin implementiert eine File-API, die Lese-/Schreibzugriff Zugriff auf Dateien, die auf dem Gerät befinden. + +Dieses Plugin basiert auf mehrere Angaben, einschließlich: die HTML5-File-API + +Die (heute nicht mehr existierenden) Verzeichnisse und System neuesten Erweiterungen: , obwohl die meisten von den Plugin-Code wurde geschrieben, als eine frühere Spec aktuell waren: + +Es implementiert auch die FileWriter Spec: + +Verwendung finden Sie in HTML5 Rocks ausgezeichnete [Dateisystem Artikel.][1] + + [1]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +Finden Sie einen Überblick über andere Speicheroptionen Cordovas [Speicher-Führer][2]. + + [2]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +Dieses Plugin wird global `cordova.file`-Objekt definiert. + +Obwohl im globalen Gültigkeitsbereich, steht es nicht bis nach dem `deviceready`-Ereignis. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## Installation + + cordova plugin add cordova-plugin-file + + +## Unterstützte Plattformen + +* Amazon Fire OS +* Android +* BlackBerry 10 +* Firefox OS +* iOS +* Windows Phone 7 und 8 * +* Windows 8 * +* Browser + +* *Diese Plattformen unterstützen nicht `FileReader.readAsArrayBuffer` noch `FileWriter.write(blob)`.* + +## Wo Dateien gespeichert + +Stand: V1 werden URLs auf wichtige Datei-System-Verzeichnisse zur Verfügung gestellt. Jede URL in der Form *file:///path/to/spot/* ist, und ein `DirectoryEntry` mit `window.resolveLocalFileSystemURL()` konvertiert werden können. + +* `cordova.file.applicationDirectory`-Die schreibgeschützten Verzeichnis, in dem die Anwendung installiert ist. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.applicationStorageDirectory`-Root-Verzeichnis der Anwendungs-Sandbox; auf iOS ist schreibgeschützt (aber bestimmte Unterverzeichnisse [wie `/Documents` ] sind Lese-und Schreibzugriff). Alle enthaltene Daten ist für die app privat. ( *iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.dataDirectory`-Beständige und private Datenspeicherung innerhalb der Anwendungs-Sandbox, die mit internen Speicher (auf Android, externen Speicher verwenden, verwenden Sie `.externalDataDirectory` ). Auf iOS, ist dieses Verzeichnis nicht mit iCloud synchronisiert (verwenden Sie `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.cacheDirectory`-Verzeichnis der zwischengespeicherten Daten-Dateien oder Dateien, die Ihre app einfach neu erstellen können. Das Betriebssystem kann diese Dateien löschen, wenn das Gerät auf Speicher knapp wird, dennoch sollten die apps vom Betriebssystem zum Löschen von Dateien hier nicht verlassen. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.externalApplicationStorageDirectory`-Anwendungsraum auf externen Speicher. (*Android*) + +* `cordova.file.externalDataDirectory`-Wo, app-spezifische Datendateien auf externen Speicher setzen. (*Android*) + +* `cordova.file.externalCacheDirectory`-Anwendungscache auf externen Speicher. (*Android*) + +* `cordova.file.externalRootDirectory`-Externer Speicher (SD-Karte) Stamm. (*Android*, *BlackBerry 10*) + +* `cordova.file.tempDirectory`-Temp-Verzeichnis, dem das OS auf deaktivieren können wird. Verlassen Sie sich nicht auf das Betriebssystem, um dieses Verzeichnis zu löschen; Ihre Anwendung sollte immer Dateien gegebenenfalls entfernen. (*iOS*) + +* `cordova.file.syncedDataDirectory`-Hält app-spezifische Dateien, die (z. B. auf iCloud) synchronisiert werden sollten. (*iOS*) + +* `cordova.file.documentsDirectory`-Dateien für die app, aber privat sind sinnvoll, andere Anwendungen (z.B. Office-Dateien). (*iOS*) + +* `cordova.file.sharedDirectory`-Dateien für alle Anwendungen (*BlackBerry 10* weltweit verfügbar) + +## Dateisystemlayouts + +Obwohl technisch ein Implementierungsdetail, kann es sehr hilfreich zu wissen, wie die `cordova.file.*`-Eigenschaften physikalische Pfade auf einem echten Gerät zugeordnet sein. + +### iOS-Datei-System-Layout + +| Gerätepfad | `Cordova.file.*` | `iosExtraFileSystems` | R/w? | persistent? | OS löscht | Sync | Private | +|:-------------------------------------------- |:--------------------------- |:--------------------- |:----:|:-----------:|:----------:|:----:|:-------:| +| `/ Var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N/A | N/A | N/A | Ja | +|    `appname.app/` | applicationDirectory | Bundle | r | N/A | N/A | N/A | Ja | +|       `www/` | - | - | r | N/A | N/A | N/A | Ja | +|    `Documents/` | documentsDirectory | Dokumente | R/w | Ja | Nein | Ja | Ja | +|       `NoCloud/` | - | Dokumente-nosync | R/w | Ja | Nein | Nein | Ja | +|    `Library` | - | Bibliothek | R/w | Ja | Nein | Ja? | Ja | +|       `NoCloud/` | dataDirectory | Bibliothek-nosync | R/w | Ja | Nein | Nein | Ja | +|       `Cloud/` | syncedDataDirectory | - | R/w | Ja | Nein | Ja | Ja | +|       `Caches/` | cacheDirectory | Cache | R/w | Ja * | Ja * * *| | Nein | Ja | +|    `tmp/` | tempDirectory | - | R/w | Nicht * * | Ja * * *| | Nein | Ja | + +* Dateien werden hinweg app Neustarts und Upgrades beibehalten, aber dieses Verzeichnis kann gelöscht werden, wenn das OS begehrt. Ihre Anwendung sollte in der Lage, Inhalte zu erschaffen, die möglicherweise gelöscht werden. + +* *-Dateien kann über app-Neustarts beizubehalten, aber verlasse dich nicht auf dieses Verhalten. Dateien sind nicht unbedingt Aktuelles beibehalten. Ihre Anwendung sollte Dateien aus diesem Verzeichnis entfernen, wenn es gilt, diese Dateien werden entfernt, da das OS nicht wann (oder auch wenn) garantiert. + +* * *| The OS kann den Inhalt dieses Verzeichnisses löschen, wenn es sich anfühlt, ist es erforderlich, aber verlassen Sie sich nicht dazu. Sie sollten dieses Verzeichnis entsprechend Ihrer Anwendung deaktivieren. + +### Android File System-Layout + +| Gerätepfad | `Cordova.file.*` | `AndroidExtraFileSystems` | R/w? | persistent? | OS löscht | Private | +|:--------------------------------- |:----------------------------------- |:------------------------- |:----:|:-----------:|:---------:|:-------:| +| `file:///android_asset/` | applicationDirectory | | r | N/A | N/A | Ja | +| `/ Data/Data/< app-Id > /` | applicationStorageDirectory | - | R/w | N/A | N/A | Ja | +|    `cache` | cacheDirectory | Cache | R/w | Ja | Ja * | Ja | +|    `files` | dataDirectory | Dateien | R/w | Ja | Nein | Ja | +|       `Documents` | | Dokumente | R/w | Ja | Nein | Ja | +| `< Sdcard > /` | externalRootDirectory | sdcard | R/w | Ja | Nein | Nein | +|    `Android/data//` | externalApplicationStorageDirectory | - | R/w | Ja | Nein | Nein | +|       `cache` | externalCacheDirectry | Cache-extern | R/w | Ja | Nicht * * | Nein | +|       `files` | externalDataDirectory | Dateien-extern | R/w | Ja | Nein | Nein | + +* Das Betriebssystem kann regelmäßig dieses Verzeichnis zu löschen, aber verlasse dich nicht auf dieses Verhalten. Deaktivieren Sie den Inhalt dieses Verzeichnisses für Ihre Anwendung geeigneten. Ein Benutzer den Cache manuell löschen sollte, werden die Inhalte dieses Verzeichnisses entfernt. + +* * The OS nicht klar dieses Verzeichnis automatisch; Sie sind verantwortlich für die Inhalte selbst verwalten. Der Benutzer den Cache manuell löschen sollte, werden der Inhalt des Verzeichnisses entfernt. + +**Hinweis**: Wenn externe Speichergeräte nicht bereitgestellt werden kann, sind die `cordova.file.external*` Eigenschaften `null`. + +### BlackBerry 10-File-System-Layout + +| Gerätepfad | `Cordova.file.*` | R/w? | persistent? | OS löscht | Private | +|:--------------------------------------------------- |:--------------------------- |:----:|:-----------:|:---------:|:-------:| +| `file:///Accounts/1000/APPDATA/ < app Id > /` | applicationStorageDirectory | r | N/A | N/A | Ja | +|    `app/native` | applicationDirectory | r | N/A | N/A | Ja | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | R/w | Nein | Ja | Ja | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | R/w | Ja | Nein | Ja | +| `file:///Accounts/1000/Removable/sdcard` | externalRemovableDirectory | R/w | Ja | Nein | Nein | +| `file:///Accounts/1000/Shared` | sharedDirectory | R/w | Ja | Nein | Nein | + +*Hinweis*: Wenn die Anwendung bereitgestellt wird, um Perimeter zu arbeiten, alle Pfade sind relativ /accounts/1000-enterprise. + +## Android Eigenarten + +### Android permanenten Speicherort + +Es gibt mehrere gültige Speicherorte, persistente Dateien auf einem Android-Gerät zu speichern. Finden Sie auf [dieser Seite][3] eine ausführliche Diskussion über die verschiedenen Möglichkeiten. + + [3]: http://developer.android.com/guide/topics/data/data-storage.html + +Frühere Versionen des Plugins wählen würde, den Speicherort der temporären und permanenten Dateien beim Start, basierend auf, ob das Gerät behauptete, dass die SD-Karte (oder gleichwertige Speicherpartition) bereitgestellt wurde. Wenn die SD-Karte eingelegt wurde, oder wenn eine große interne Speicherpartition verfügbar war (wie auf Nexus-Geräten) und dann in die Wurzel dieses Raumes, die persistenten Dateien gespeichert werden. Dies bedeutete, dass alle Cordova apps aller verfügbaren Dateien auf der Karte sehen konnte. + +Wenn die SD-Karte nicht verfügbar war, dann Vorgängerversionen Daten unter speichern würde `/data/data/`, die isoliert Anwendungen voneinander, aber möglicherweise noch Ursache Daten zwischen Benutzern freigegeben werden. + +Es ist jetzt möglich, ob Sie Dateien der internen Datei-Speicherort oder unter Verwendung der bisherigen Logik, mit einer Präferenz in der Anwendung-`config.xml`-Datei speichern möchten. Hierzu fügen Sie eine dieser zwei Zeilen zu `"config.xml"`: + + + + + + +Ohne diese Zeile wird das Datei Plugin `Compatibility` als Standard verwenden. Wenn ein Präferenz-Tag vorhanden ist, und nicht einen der folgenden Werte, wird die Anwendung nicht gestartet. + +Wenn Ihre Anwendung für Benutzer zuvor versandt wird, mithilfe eines älteren (Pre-1.0) Version dieses Plugins und gespeicherte Dateien im permanenten Dateisystem hat, dann sollten Sie die Einstellung zur `Compatibility` einstellen. Wechseln die Location auf "Internal" würde bedeuten, dass Benutzer, die aktualisieren Sie ihre Anwendung, möglicherweise nicht auf ihre zuvor gespeicherte Dateien, abhängig von ihrem Gerät zugreifen. + +Wenn Ihre Anwendung neu ist, oder nie zuvor Dateien im Dateisystem persistent gespeichert hat, wird die `Internal` Einstellung in der Regel empfohlen. + +## iOS Macken + +* `cordova.file.applicationStorageDirectory`ist schreibgeschützt; zum Speichern von Dateien im Stammverzeichnis der Versuch schlägt fehl. Verwenden Sie eine der anderen `cordova.file.*` für iOS definierten Eigenschaften (nur `applicationDirectory` und `applicationStorageDirectory` sind schreibgeschützt). +* `FileReader.readAsText(blob, encoding)` + * Die `encoding` Parameter wird nicht unterstützt und UTF-8-Kodierung ist immer wirksam. + +### iOS permanenten Speicherort + +Es gibt zwei gültige Speicherorte persistente Dateien auf ein iOS-Gerät speichern: das Dokumenten-Verzeichnis und das Verzeichnis Library. Frühere Versionen des Plugins gespeichert immer nur persistente Dateien im Verzeichnis Dokumente. Dies hatte den Nebeneffekt einer Anwendung Dateien in iTunes, die oft unbeabsichtigte, speziell für Anwendungen, die viele kleine Dateien behandeln war, sichtbar zu machen, anstatt komplette Dokumente für den Export, die den beabsichtigten Zweck des Verzeichnisses ist zu produzieren. + +Es ist jetzt möglich, ob Sie Dateien in Dokumente oder Verzeichnis Library mit einer Präferenz in der Anwendung-`config.xml`-Datei speichern möchten. Hierzu fügen Sie eine dieser zwei Zeilen zu `"config.xml"`: + + + + + + +Ohne diese Zeile wird das Datei Plugin `Compatibility` als Standard verwenden. Wenn ein Präferenz-Tag vorhanden ist, und nicht einen der folgenden Werte, wird die Anwendung nicht gestartet. + +Wenn Ihre Anwendung für Benutzer zuvor versandt wird, mithilfe eines älteren (Pre-1.0) Version dieses Plugins und gespeicherte Dateien im permanenten Dateisystem hat, dann sollten Sie die Einstellung zur `Compatibility` einstellen. Standort zur `Library` wechseln würde bedeuten, dass Benutzer, die ihre Anwendung aktualisieren nicht in der Lage wäre, ihre zuvor gespeicherte Dateien zugreifen. + +Wenn die Anwendung neu, oder nie zuvor Dateien im Dateisystem persistent gespeichert hat, wird die Einstellung der `Library` allgemein empfohlen. + +## Firefox OS Macken + +Der Datei-System-API wird von Firefox-OS nicht nativ unterstützt und wird als ein Shim auf IndexedDB implementiert. + +* Schlägt nicht fehl, wenn Sie nicht leere Verzeichnisse entfernen +* Metadaten wird für Verzeichnisse nicht unterstützt. +* Methoden `copyTo` und `moveTo` unterstützen keine Verzeichnisse + +Die folgenden Datenpfade werden unterstützt: * `applicationDirectory` - `xhr` verwendet, um lokale Dateien erhalten, die mit der app verpackt sind. *`dataDirectory` - für persistente app-spezifische Daten-Dateien. *`cacheDirectory` - Cache-Dateien, die app startet überleben sollte (Apps sollten nicht vom Betriebssystem zum Löschen von Dateien hier verlassen). + +## Browser-Eigenheiten + +### Gemeinsamen Macken und Bemerkungen + +* Jeder Browser verwendet ein eigene Sandbox Dateisystem. IE und Firefox verwenden IndexedDB als Basis. Alle Browser verwenden Schrägstrich als Verzeichnistrennzeichen in einem Pfad. +* Directory-Einträge müssen nacheinander erstellt werden. Z. B. der Aufruf `fs.root.getDirectory ("dir1/Ordner2 ', {create:true}, SuccessCallback, ErrorCallback)` schlägt fehl, wenn dir1 nicht existierte. +* Das Plugin fordert Benutzer die Berechtigung zum permanenten Speicher beim ersten Start Anwendung verwenden. +* Plugin unterstützt `Cdvfile://localhost` (lokale Ressourcen) nur. D.h. externe Ressourcen nicht über `Cdvfile` unterstützt. +* Das Plugin folgt nicht ["File System API 8.3 Naming Einschränkungen"][4]. +* BLOB und Datei "`close`-Funktion wird nicht unterstützt. +* `FileSaver` und `BlobBuilder` werden von diesem Plugin nicht unterstützt und müssen nicht geboren. +* Das Plugin unterstützt keine `RequestAllFileSystems`. Diese Funktion fehlt auch in den Spezifikationen. +* Einträge im Verzeichnis werden nicht entfernt werden, wenn Sie verwenden `create: true` Flag für vorhandenes Verzeichnis. +* Über Konstruktor erstellte Dateien werden nicht unterstützt. Sie sollten stattdessen die entry.file-Methode verwenden. +* Jeder Browser verwendet eine eigene Form für Blob-URL-Verweise. +* `readAsDataURL`-Funktion wird unterstützt, aber die Mediatype in Chrom hängt von der Eintrag Namenerweiterung, Mediatype im IE immer leer ist (das ist dasselbe wie `Text-Plain` gemäß der Spezifikation), Mediatype in Firefox ist immer `Application/Octet-Stream`. Beispielsweise, wenn der Inhalt `Abcdefg` gibt dann Firefox `Daten: Anwendung / Octet-Stream; base64, YWJjZGVmZw ==`, IE gibt `Daten:; base64, YWJjZGVmZw ==`, Chrom gibt `Daten: < Mediatype je nach Erweiterung des Eintragsnamens >; base64, YWJjZGVmZw ==`. +* `ToInternalURL` gibt den Pfad zurück, in der Form `file:///persistent/path/to/entry` (Firefox, IE). Chrom gibt den Pfad zurück, in der Form `cdvfile://localhost/persistent/file`. + + [4]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions + +### Chrom-Macken + +* Chrom-Dateisystem ist nicht sofort nach Gerät bereit. Als Workaround können Sie `FilePluginIsReady`-Ereignis abonnieren. Beispiel: + + javascript + window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); + + +`Window.isFilePluginReadyRaised`-Funktion können Sie überprüfen, ob Ereignis bereits ausgelöst wurde. -window.requestFileSystem temporär und PERSISTENTE Dateisystem-Quoten sind nicht begrenzt, in Chrom. -Um die dauerhafte Speicherung in Chrom zu erhöhen benötigen Sie `window.initPersistentFileSystem`-Methode aufrufen. Permanenter Speicherkontingent beträgt 5 MB standardmäßig. -Chrome erforderlich `--erlauben-Datei-Zugriff-aus-Files` Argument an den Support API via `file:///` Protokoll führen. -`Datei`-Objekt wird nicht geändert werden, wenn Sie Flag verwenden `{create:true}` als einen vorhandenen `Eintrag` zu erhalten. -Veranstaltungen `cancelable`-Eigenschaft festgelegt ist in Chrom wahr. Dies widerspricht der [Spezifikation][5]. -`toURL`-Funktion in Chrome zurück `Dateisystem:`-Pfad je nach Anwendungshost vorangestellt. Z. B. `filesystem:file:///persistent/somefile.txt`, `Filesystem:http://localhost:8080/persistent/somefile.txt`. -`toURL` Funktionsergebnis enthält keine nachgestellten Schrägstrich bei Verzeichniseintrag. Chrom löst Verzeichnisse mit Schrägstrich-gezogene Urls aber korrekt. -`ResolveLocalFileSystemURL`-Methode erfordert die eingehenden `Url` `Dateisystem` Präfix haben. Beispielsweise sollte die `Url`-Parameter für `ResolveLocalFileSystemURL` in der Form `filesystem:file:///persistent/somefile.txt` im Gegensatz zu der Form `file:///persistent/somefile.txt` in Android. -Veraltete `ToNativeURL`-Funktion wird nicht unterstützt und muss keinen Stub. -`SetMetadata`-Funktion ist nicht in den Spezifikationen angegeben und nicht unterstützt. -INVALID_MODIFICATION_ERR (Code: 9) wird ausgelöst, statt SYNTAX_ERR(code: 8) auf anfordern des Dateisystems nicht existent. -INVALID_MODIFICATION_ERR (Code: 9) wird ausgelöst, anstatt PATH_EXISTS_ERR(code: 12) zu versuchen, die ausschließlich eine Datei oder ein Verzeichnis zu erstellen, die bereits vorhanden ist. -INVALID_MODIFICATION_ERR (Code: 9) wird ausgelöst, anstatt NO_MODIFICATION_ALLOWED_ERR(code: 6) zu versuchen, rufen Sie RemoveRecursively auf das Root-Dateisystem. -INVALID_MODIFICATION_ERR (Code: 9) wird ausgelöst, anstatt NOT_FOUND_ERR(code: 1) zu versuchen, MoveTo-Verzeichnis, das nicht vorhanden ist. + + [5]: http://dev.w3.org/2009/dap/file-system/file-writer.html + +### Auf der Grundlage von IndexedDB Impl Macken (Firefox und IE) + +* `.` und `.` werden nicht unterstützt. +* IE unterstützt keine `file:///`-Modus; nur der Modus für gehostete ist unterstützten (Http://localhost:xxxx). +* Firefox Dateisystem Größe ist nicht begrenzt, aber jede 50MB-Erweiterung wird eine Benutzer die Berechtigung anzufordern. IE10 können bis zu 10mb kombinierte AppCache und IndexedDB in Implementierung des Dateisystems verwendet, ohne Aufforderung, sobald Sie dieses Niveau, werden, das Sie aufgefordert werden schlagen, wenn Sie es bis Max 250 mb pro Standort erhöht werden sollen. `Size`-Parameter für `RequestFileSystem` Funktion wirkt also nicht Dateisystem in Firefox und IE. +* `ReadAsBinaryString` Funktion heißt es nicht in die Angaben und in IE nicht unterstützt und muss keinen Stub. +* `file.Type` ist immer null. +* Sie sollten nicht erstellen Eintrag mit DirectoryEntry Instanz Rückrufergebnis, die gelöscht wurde. Andernfalls erhalten Sie einen "hängende Eintrag". +* Bevor Sie eine Datei lesen können, die gerade geschrieben wurde, müssen Sie eine neue Instanz dieser Datei erhalten. +* `SetMetadata`-Funktion, die nicht in den Specs genannt unterstützt Feldänderung nur `ModificationTime`. +* `CopyTo` und `MoveTo`-Funktionen unterstützen keine Verzeichnisse. +* Verzeichnisse-Metadaten werden nicht unterstützt. +* Beide Entry.remove und directoryEntry.removeRecursively nicht scheitern, wenn nicht leere Verzeichnisse entfernen - Verzeichnisse entfernt werden stattdessen zusammen mit Inhalt gereinigt. +* `abort` und `truncate`-Funktionen werden nicht unterstützt. +* Progress-Ereignisse werden nicht ausgelöst. Beispielsweise wird dieser Handler nicht ausgeführt werden: + + javascript + writer.onprogress = function() { /*commands*/ }; + + +## Upgrade Notes + +In v1.0.0 dieses Plugins haben die `FileEntry` und `DirectoryEntry` Strukturen geändert, um mehr im Einklang mit der veröffentlichten Spezifikation sein. + +Vorgängerversionen (Pre-1.0.0) des Plugins den Gerät-Absolute-Dateispeicherort in der Eigenschaft `fullPath` `Entry` Objekte gespeichert. Diese Pfade würde in der Regel aussehen + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Diese Pfade wurden auch von der `toURL()`-Methode der `Entry` Objekte zurückgegeben. + +Mit v1.0.0 ist das `fullPath`-Attribut den Pfad zu der Datei, *relativ zum Stammverzeichnis des Dateisystems HTML*. Also, würde die oben genannten Wege jetzt beide durch ein `FileEntry`-Objekt mit einem `fullPath` von dargestellt werden + + /path/to/file + + +Wenn Ihre Anwendung mit absoluter Gerätepfade arbeitet und Sie zuvor diese Pfade durch die Eigenschaft `fullPath` `Entry` Objekte abgerufen, sollten dann Sie den Code, um stattdessen `entry.toURL()` verwenden aktualisieren. + +Für rückwärts Kompatibilität, die `resolveLocalFileSystemURL()`-Methode wird einen Absolute-Gerätepfad zu akzeptieren und kehrt ein `Entry`-Objekt entspricht, solange diese Datei in den `TEMPORARY` oder `PERSISTENT` Dateisysteme existiert. + +Dies wurde vor allem ein Problem mit dem File-Transfer-Plugin, die zuvor-Absolute-Gerätepfade verwendet (und kann damit noch einverstanden). Es wurde überarbeitet, um mit Dateisystem-URLs korrekt zu arbeiten, damit ersetzen `entry.fullPath` mit `entry.toURL()` immer das Plugin zum Arbeiten mit Dateien auf dem Gerät Probleme lösen sollte. + +In v1.1.0 wurde der Rückgabewert von `toURL()` (siehe \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) geändert, um eine absolute "file://" URL zurückgeben. wo immer möglich. Sicherstellung einer ' Cdvfile:'-URL können Sie an `toInternalURL()`. Diese Methode gibt jetzt Dateisystem URLs der Form zurück. + + cdvfile://localhost/persistent/path/to/file + + +die benutzt werden können, um die Datei eindeutig zu identifizieren. + +## Liste der Fehlercodes und Bedeutungen + +Wenn ein Fehler ausgelöst wird, wird eines der folgenden Codes verwendet werden. + +| Code | Konstante | +| ----:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Konfigurieren das Plugin (Optional) + +Die Menge der verfügbaren Dateisysteme kann pro Plattform konfiguriert sein. Erkennen von iOS und Android ein Tag in `"config.xml"` die Namen der Dateisysteme installiert werden. Standardmäßig sind alle Datei-System-Roots aktiviert. + + + + + +### Android + +* `files`: interne Datei-Speicher-Verzeichnis der Anwendung +* `files-external`: Verzeichnis der Anwendung externe Datei Speicher +* `sdcard`: das externe Globaldatei-Speicherverzeichnis (Dies ist die Wurzel der SD-Karte, sofern installiert). Sie benötigen die Berechtigung zur Verwendung dieses `android.permission.WRITE_EXTERNAL_STORAGE`. +* `cache`: internen Cache-Verzeichnis der Anwendung +* `cache-external`: externer Cache-Verzeichnis der Anwendung +* `root`: das gesamte Gerät-Dateisystem + +Android unterstützt auch eine spezielle Dateisystem mit dem Namen "documents", die ein Unterverzeichnis "/Documents/" die "files" Dateisystem darstellt. + +### iOS + +* `library`: Bibliothek-Verzeichnis der Anwendung +* `documents`: Dokumente-Verzeichnis der Anwendung +* `cache`: Cache-Verzeichnis der Anwendung +* `bundle`: die Anwendung Bündel; den Speicherort der die app selbst auf dem Datenträger (schreibgeschützt) +* `root`: das gesamte Gerät-Dateisystem + +Standardmäßig können die Bibliothek und Dokumenten-Verzeichnisse mit iCloud synchronisiert werden. Sie können auch verlangen, zwei zusätzliche Dateisysteme, `library-nosync` und `documents-nosync`, die einem speziellen nicht synchronisierten Verzeichnis innerhalb darstellen der `/Library` oder `/Documents`-Dateisystem. diff --git a/mobile/plugins/cordova-plugin-file/doc/de/plugins.md b/mobile/plugins/cordova-plugin-file/doc/de/plugins.md new file mode 100644 index 0000000..8887d7a --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/de/plugins.md @@ -0,0 +1,101 @@ + + +# Hinweise für Plugin-Entwickler + +Diese Notizen sind hauptsächlich für Android und iOS-Entwickler, die Plugins welche Schnittstelle mit dem Dateisystem, mit dem Plugin Datei schreiben möchten. + +## Arbeiten mit Cordova-Datei-System-URLs + +Seit der Version 1.0.0, wurde dieses Plugin verwendet URLs mit einer `cdvfile` Regelung für die gesamte Kommunikation über die Brücke, sondern als raw-Device Dateisystempfade zu JavaScript auszusetzen. + +Auf der Seite JavaScript bedeutet dies, dass FileEntries und DirectoryEntry-Objekt ein FullPath-Attribut haben, die relativ zum Stammverzeichnis des Dateisystems HTML ist. Wenn Ihr Plugins-JavaScript-API ein FileEntries oder DirectoryEntry-Objekt akzeptiert, rufen Sie `.toURL()` auf das Objekt vor der Übergabe an systemeigenen Code über die Brücke. + +### Konvertieren von Cdvfile: / / URLs auf Fileystem Pfade + +Plugins, die auf das Dateisystem schreiben müssen, sollten eine empfangene Datei-System-URL auf eine tatsächliche Stelle des Dateisystems zu konvertieren. Es gibt mehrere Wege, dies zu tun, je nach einheitlichen Plattform. + +Es ist wichtig, daran erinnern, dass nicht alle `cdvfile://` URLs sind zuweisbaren real Dateien auf das Gerät. Einige URLs verweisen auf Vermögenswerte auf Gerät nicht durch Dateien dargestellt werden, oder sogar auf Remoteressourcen verweisen können. Aufgrund dieser Möglichkeiten sollten Plugins immer testen, ob sie ein sinnvolles Ergebnis zu erhalten, wieder bei dem Versuch, die URLs in Pfade umwandeln. + +#### Android + +Auf Android, konvertiert die einfachste Methode eine `cdvfile://` URL zu einem Dateisystempfad zu verwenden ist `org.apache.cordova.CordovaResourceApi` . `CordovaResourceApi`verfügt über mehrere Methoden der verarbeiten kann `cdvfile://` URLs: + + WebView ist Mitglied der Plugin-Klasse CordovaResourceApi ResourceApi = webView.getResourceApi(); + + Erhalten eine file:/// URL, diese Datei auf dem Gerät / / oder die gleiche URL unverändert, wenn es eine Datei-Uri FileURL zugeordnet werden kann nicht = resourceApi.remapUri(Uri.parse(cdvfileURL)); + + +Es ist auch möglich, das Plugin Datei direkt zu verwenden: + + Import org.apache.cordova.file.FileUtils; + Import org.apache.cordova.file.FileSystem; + Import Java.net.MalformedURLException:; + + Erhalten Sie das Datei-Plugin aus dem Plugin-Manager FileUtils FilePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + Angesichts eine URL, einen Pfad zu erhalten, denn es versuchen {String Pfad = filePlugin.filesystemPathForURL(cdvfileURL);} catch (MalformedURLException e) {/ / die Dateisystem-Url war nicht erkannt} + + +Aus einem Pfad zu konvertieren eine `cdvfile://` URL: + + Import org.apache.cordova.file.LocalFilesystemURL; + + Rufen Sie ein LocalFilesystemURL-Objekt für einen Gerätepfad / / oder null, wenn sie nicht als URL Cdvfile dargestellt wird. + LocalFilesystemURL Url = filePlugin.filesystemURLforLocalPath(path); + Erhalten Sie die Zeichenfolgendarstellung der URL Objekt String CdvfileURL = url.toString(); + + +Wenn Ihr Plugin eine Datei erstellt, und Sie dafür ein FileEntries-Objekt zurückgeben möchten, verwenden Sie das Datei-Plugin: + + Zurückgeben eine JSON-Struktur geeignet für die Rückgabe an JavaScript, / / oder null, wenn diese Datei nicht als URL Cdvfile darstellbar ist. + JSONObject Eintrag = filePlugin.getEntryForFile(file); + + +#### iOS + +Cordova auf iOS verwendet nicht das gleiche `CordovaResourceApi` Konzept als Android. Auf iOS sollten Sie das Datei-Plugin verwenden, zum Konvertieren von URLs und Dateisystem-Pfaden. + + Rufen Sie ein CDVFilesystem URL-Objekt von einer URL-Zeichenfolge CDVFilesystemURL * Url = [CDVFilesystemURL FileSystemURLWithString:cdvfileURL]; + Erhalten Sie einen Pfad für die URL-Objekt oder NULL, wenn es einen Dateipfad NSString * zugeordnet werden kann nicht = [FilePlugin FilesystemPathForURL:url]; + + + Eine CDVFilesystem URL-Objekt für einen Gerätepfad abrufen oder / / gleich NULL, wenn sie nicht als URL Cdvfile dargestellt wird. + CDVFilesystemURL-Url = [FilePlugin FileSystemURLforLocalPath:path]; + Erhalten Sie die Zeichenfolgendarstellung der URL Objekt NSString * CdvfileURL = [Url AbsoluteString]; + + +Wenn Ihr Plugin eine Datei erstellt, und Sie dafür ein FileEntries-Objekt zurückgeben möchten, verwenden Sie das Datei-Plugin: + + Eine CDVFilesystem URL-Objekt für einen Gerätepfad abrufen oder / / gleich NULL, wenn sie nicht als URL Cdvfile dargestellt wird. + CDVFilesystemURL-Url = [FilePlugin FileSystemURLforLocalPath:path]; + Erhalten eine Struktur zurück nach JavaScript NSDictionary * Eintrag = [FilePlugin MakeEntryForLocalURL:url] + + +#### JavaScript + +In JavaScript, bekommen eine `cdvfile://` URL aus einem FileEntries oder DirectoryEntry-Objekt, rufen Sie einfach `.toURL()` drauf: + + Var CdvfileURL = entry.toURL(); + + +Im Plugin Antwort Handler zur Konvertierung von einer zurückgegebenen FileEntries-Struktur in einem tatsächlichen Eintrag-Objekt sollte Handlercode importieren die Datei-Erweiterung und ein neues Objekt zu erstellen: + + Erstellen Sie entsprechenden Eintrag Objekt Var Eintrag; + Wenn (entryStruct.isDirectory) {Eintrag = neues DirectoryEntry (entryStruct.name, entryStruct.fullPath, neue FileSystem(entryStruct.filesystemName));} sonst {Eintrag = neue FileEntries (entryStruct.name, entryStruct.fullPath, neue FileSystem(entryStruct.filesystemName));} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/es/README.md b/mobile/plugins/cordova-plugin-file/doc/es/README.md new file mode 100644 index 0000000..2a653bf --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/es/README.md @@ -0,0 +1,335 @@ + + +# cordova-plugin-file + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg)](https://travis-ci.org/apache/cordova-plugin-file) + +Este plugin implementa una API de archivo que permite acceso de lectura/escritura a los archivos que residen en el dispositivo. + +Este plugin se basa en varias especificaciones, incluyendo: el HTML5 archivo API + +Los directorios (ahora extinto) y sistema de extensiones más recientes: aunque la mayor parte del código del plugin fue escrito cuando una especificación anterior era actual: + +También implementa la especificación de FileWriter: + +Para el uso, por favor, consulte 'HTML5 Rocks excelente [FileSystem artículo.](http://www.html5rocks.com/en/tutorials/file/filesystem/) + +Para tener una visión general de otras opciones de almacenamiento, consulte [Guía de almacenamiento Cordova](http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html). + +Este plugin define global `cordova.file` objeto. + +Aunque en el ámbito global, no estará disponible hasta después de la `deviceready` evento. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## Instalación + + cordova plugin add cordova-plugin-file + + +## Plataformas soportadas + + * Amazon fire OS + * Android + * BlackBerry 10 + * Firefox OS + * iOS + * Windows Phone 7 y 8 * + * Windows 8 * + * Windows* + * Explorador + +\* *These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`.* + +## Donde almacenar los archivos + +A partir de v1.2.0, URLs a directorios de sistema de archivos importantes son proporcionadas. Cada dirección URL está en la forma *file:///path/to/spot/*y se puede convertir en un `DirectoryEntry` usando`window.resolveLocalFileSystemURL()`. + + * `cordova.file.applicationDirectory`-Directorio Read-only donde está instalada la aplicación. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.applicationStorageDirectory`-Directorio del entorno limitado de la aplicación; en iOS esta ubicación es de sólo lectura (pero subdirectorios específicos [como `/Documents` ] son de lectura y escritura). Todos los datos contenidos dentro es privado para la aplicación. ( *iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.dataDirectory`-Almacenamiento de datos persistente y privadas dentro de entorno limitado de la aplicación utilizando la memoria interna (en Android, si necesitas usar memoria externa, use `.externalDataDirectory` ). En iOS, este directorio no está sincronizado con iCloud (utilice `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.cacheDirectory`-Directorio para los archivos de datos almacenados en caché o los archivos que su aplicación puede volver a crear fácilmente. El sistema operativo puede borrar estos archivos cuando el dispositivo se agota en almacenamiento de información, sin embargo, aplicaciones no deben confiar en el sistema operativo para eliminar los archivos de aquí. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.externalApplicationStorageDirectory`-Espacio aplicación de almacenamiento externo. (*Android*) + + * `cordova.file.externalDataDirectory`¿Dónde poner los archivos de datos específicos de la aplicación de almacenamiento externo. (*Android*) + + * `cordova.file.externalCacheDirectory`-Caché aplicación de almacenamiento externo. (*Android*) + + * `cordova.file.externalRootDirectory`-Raíz de almacenamiento externo (tarjeta SD). (*Android*, *BlackBerry 10*) + + * `cordova.file.tempDirectory`-Directorio temporal que puede borrar el sistema operativo en sí. No confíe en el sistema operativo para borrar este directorio; su aplicación siempre debe eliminar archivos según corresponda. (*iOS*) + + * `cordova.file.syncedDataDirectory`-Contiene los archivos de la aplicación específica que deben ser sincronizados (e.g. a iCloud). (*iOS*) + + * `cordova.file.documentsDirectory`-Archivos privados a la aplicación, pero que son significativos para otra aplicación (por ejemplo archivos de Office). (*iOS*) + + * `cordova.file.sharedDirectory`-Archivos disponibles globalmente para todas las aplicaciones (*BlackBerry 10*) + +## Diseños de sistema de archivo + +Aunque técnicamente un detalle de la implementación, puede ser muy útil saber cómo la `cordova.file.*` mapa de propiedades en trazados físicos en un dispositivo real. + +### iOS diseño de sistema de archivo + +| Ruta de dispositivo | `Cordova.file.*` | `iosExtraFileSystems` | ¿r/w? | ¿persistente? | OS despeja | sincronización | privado | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:-----:|:-------------:|:-------------:|:--------------:|:-------:| +| `/ var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N / A | N / A | N / A | Sí | +|    `appname.app/` | applicationDirectory | Bundle | r | N / A | N / A | N / A | Sí | +|       `www/` | - | - | r | N / A | N / A | N / A | Sí | +|    `Documents/` | documentsDirectory | documentos | r/w | Sí | No | Sí | Sí | +|       `NoCloud/` | - | documentos-nosync | r/w | Sí | No | No | Sí | +|    `Library` | - | Biblioteca | r/w | Sí | No | ¿Sí? | Sí | +|       `NoCloud/` | dataDirectory | Biblioteca-nosync | r/w | Sí | No | No | Sí | +|       `Cloud/` | syncedDataDirectory | - | r/w | Sí | No | Sí | Sí | +|       `Caches/` | cacheDirectory | caché | r/w | Sí * | Yes**\* | No | Sí | +|    `tmp/` | tempDirectory | - | r/w | No** | Yes**\* | No | Sí | + +\ * Archivos persisten a través de reinicios de aplicación y actualizaciones, pero este directorio puede ser despejó cuando el OS deseos. Su aplicación debe ser capaz de recrear cualquier contenido que puede ser eliminado. + +** Archivos puede persistir a través de la aplicación se reinicia, pero no confiar en este comportamiento. Los archivos no se garantizan que persisten a través de actualizaciones. Su aplicación debe eliminar los archivos de este directorio cuando es aplicable, como el sistema operativo no garantiza cuando (o incluso si) estos archivos se quitan. + +**\ * OS la puede borrar el contenido de este directorio siempre que se siente es necesario, pero no dependen de esto. Debe borrar este directorio según sea apropiado para su aplicación. + +### Disposición del sistema Android File + +| Ruta de dispositivo | `Cordova.file.*` | `AndroidExtraFileSystems` | ¿r/w? | ¿persistente? | OS despeja | privado | +|:------------------------------------------------ |:----------------------------------- |:------------------------- |:-----:|:-------------:|:----------:|:-------:| +| `File:///android_asset/` | applicationDirectory | | r | N / A | N / A | Sí | +| `/Data/data/< id de aplicación > /` | applicationStorageDirectory | - | r/w | N / A | N / A | Sí | +|    `cache` | cacheDirectory | caché | r/w | Sí | Sí \ * | Sí | +|    `files` | dataDirectory | archivos | r/w | Sí | No | Sí | +|       `Documents` | | documentos | r/w | Sí | No | Sí | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | Sí | No | No | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Sí | No | No | +|       `cache` | externalCacheDirectry | caché-externo | r/w | Sí | No** | No | +|       `files` | externalDataDirectory | archivos externos | r/w | Sí | No | No | + +\ * El sistema operativo periódicamente puede borrar este directorio, pero no confiar en este comportamiento. Borrar el contenido de este directorio según sea apropiado para su aplicación. El contenido de este directorio debe un usuario purga la caché manualmente, se eliminan. + +** El sistema operativo no borrar este directorio automáticamente; usted es responsable de administrar el contenido usted mismo. Deberá el usuario purga la caché manualmente, se extraen los contenidos del directorio. + +**Nota**: Si no se puede montar de almacenamiento externo, el `cordova.file.external*` Propiedades`null`. + +### Disposición del sistema blackBerry 10 archivo + +| Ruta de dispositivo | `Cordova.file.*` | ¿r/w? | ¿persistente? | OS despeja | privado | +|:------------------------------------------------------------- |:--------------------------- |:-----:|:-------------:|:----------:|:-------:| +| `File:///accounts/1000/AppData/ < id de aplicación > /` | applicationStorageDirectory | r | N / A | N / A | Sí | +|    `app/native` | applicationDirectory | r | N / A | N / A | Sí | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | No | Sí | Sí | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Sí | No | Sí | +| `File:///accounts/1000/Removable/sdcard` | externalRemovableDirectory | r/w | Sí | No | No | +| `File:///accounts/1000/shared` | sharedDirectory | r/w | Sí | No | No | + +*Nota*: cuando se implementa la aplicación al trabajo de perímetro, todos los caminos son relativos a /accounts/1000-enterprise. + +## Rarezas Android + +### Ubicación de almacenamiento persistente Android + +Hay múltiples ubicaciones válidas para almacenar archivos persistentes en un dispositivo Android. Vea [esta página](http://developer.android.com/guide/topics/data/data-storage.html) para una extensa discusión de las distintas posibilidades. + +Las versiones anteriores del plugin elegiría la ubicación de los archivos temporales y persistentes en el arranque, basado en si el dispositivo afirmó que fue montado en la tarjeta SD (o partición de almacenamiento equivalente). Si fue montada en la tarjeta SD, o una partición de gran almacenamiento interno estaba disponible (como en dispositivos de Nexus,) y luego los archivos persistentes se almacenaría en la raíz de ese espacio. Esto significaba que todas las apps Cordova podían ver todos los archivos disponibles en la tarjeta. + +Si la tarjeta SD no estaba disponible, entonces versiones anteriores podría almacenar datos debajo de `/data/data/` , que aísla las apps del otro, pero puede todavía causa datos para ser compartido entre los usuarios. + +Ahora es posible elegir si desea almacenar archivos en la ubicación de almacenamiento del archivo interno, o usando la lógica anterior, con una preferencia en de la aplicación `config.xml` archivo. Para ello, añada una de estas dos líneas a `config.xml` : + + + + + + +Sin esta línea, se utilizará el archivo plugin `Compatibility` como valor predeterminado. Si una etiqueta de preferencia está presente y no es uno de estos valores, no se iniciará la aplicación. + +Si su solicitud se ha enviado previamente a los usuarios, usando un mayor (1.0 pre) versión de este plugin y archivos almacenados en el sistema de ficheros persistente, entonces debería establecer la preferencia en `Compatibility` . Cambiar la ubicación para "Internal" significa que los usuarios existentes que actualización su aplicación pueden ser incapaces de acceder a sus archivos previamente almacenadas, dependiendo de su dispositivo. + +Si su solicitud es nuevo, o nunca antes ha almacenado archivos en el sistema de ficheros persistente, entonces el `Internal` generalmente se recomienda el ajuste. + +### Operaciones recursivas lento para /android_asset + +Listado de directorios activos es realmente lento en Android. Usted puede acelerar hacia arriba, agregando `src/android/build-extras.gradle` a la raíz de tu proyecto android (también requiere de cordova-android@4.0.0 o mayor). + +## iOS rarezas + + * `cordova.file.applicationStorageDirectory`es de sólo lectura; intentar almacenar archivos en el directorio raíz fallará. Utilice uno de los `cordova.file.*` las propiedades definidas para iOS (sólo `applicationDirectory` y `applicationStorageDirectory` son de sólo lectura). + * `FileReader.readAsText(blob, encoding)` + * El `encoding` no se admite el parámetro, y codificación UTF-8 es siempre en efecto. + +### iOS ubicación de almacenamiento persistente + +Hay dos ubicaciones válidas para almacenar archivos persistentes en un dispositivo iOS: el directorio de documentos y el directorio de biblioteca. Las versiones anteriores del plugin sólo almacenan archivos persistentes en el directorio de documentos. Esto tenía el efecto secundario de todos los archivos de la aplicación haciendo visible en iTunes, que era a menudo involuntarios, especialmente para aplicaciones que manejan gran cantidad de archivos pequeños, en lugar de producir documentos completos para la exportación, que es la finalidad del directorio. + +Ahora es posible elegir si desea almacenar archivos en los documentos o directorio de bibliotecas, con preferencia en de la aplicación `config.xml` archivo. Para ello, añada una de estas dos líneas a `config.xml` : + + + + + + +Sin esta línea, se utilizará el archivo plugin `Compatibility` como valor predeterminado. Si una etiqueta de preferencia está presente y no es uno de estos valores, no se iniciará la aplicación. + +Si su solicitud se ha enviado previamente a los usuarios, usando un mayor (1.0 pre) versión de este plugin y archivos almacenados en el sistema de ficheros persistente, entonces debería establecer la preferencia en `Compatibility` . Cambiar la ubicación de `Library` significa que los usuarios existentes que actualización su aplicación sería incapaces de acceder a sus archivos previamente almacenadas. + +Si su solicitud es nuevo, o nunca antes ha almacenado archivos en el sistema de ficheros persistente, entonces el `Library` generalmente se recomienda el ajuste. + +## Firefox OS rarezas + +La API de sistema de archivo de forma nativa no es compatible con Firefox OS y se implementa como una cuña en la parte superior indexedDB. + + * No falla cuando eliminar directorios no vacía + * No admite metadatos para directorios + * Los métodos `copyTo` y `moveTo` no son compatibles con directorios + +Se admiten las siguientes rutas de datos: * `applicationDirectory` -usa `xhr` para obtener los archivos locales que están envasados con la aplicación. * `dataDirectory` - Para archivos de datos específicos de aplicación persistente. * `cacheDirectory` -En caché archivos que deben sobrevivir se reinicia la aplicación (aplicaciones no deben confiar en el sistema operativo para eliminar archivos aquí). + +## Navegador rarezas + +### Rarezas y observaciones comunes + + * Cada navegador utiliza su propio sistema de ficheros un espacio aislado. IE y Firefox utilizan IndexedDB como base. Todos los navegadores utilizan diagonal como separador de directorio en un camino. + * Las entradas de directorio deben crearse sucesivamente. Por ejemplo, la llamada `fs.root.getDirectory (' dir1/dir2 ', {create:true}, successCallback, errorCallback)` se producirá un error si no existiera dir1. + * El plugin solicita permiso de usuario para usar almacenamiento persistente en el primer comienzo de la aplicación. + * Plugin soporta `cdvfile://localhost` (recursos locales) solamente. Es decir, no se admiten los recursos externos vía `cdvfile`. + * El plugin no sigue ["Archivo sistema API 8.3 nombrando restricciones"](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions). + * BLOB y archivo ' `close` la función no es compatible. + * `FileSaver` y `BlobBuilder` no son compatibles con este plugin y no tengo recibos. + * El plugin no es compatible con `requestAllFileSystems`. Esta función también está desaparecida en las especificaciones. + * No se quitarán las entradas de directorio Si utilizas `create: true` bandera de directorio existente. + * No se admiten archivos creados mediante el constructor. Debe utilizar método entry.file en su lugar. + * Cada navegador utiliza su propia forma de blob URL referencias. + * se admite la función `readAsDataURL`, pero el mediatype en cromo depende de la extensión de nombre de entrada, mediatype en IE siempre está vacío (que es lo mismo como `plain-text` según la especificación), el mediatype en Firefox siempre es `application/octet-stream`. Por ejemplo, si el contenido es `abcdefg` entonces Firefox devuelve `datos: aplicación / octet-stream; base64, YWJjZGVmZw ==`, es decir devuelve `datos:; base64, YWJjZGVmZw ==`, cromo devuelve `datos: < mediatype dependiendo de la extensión de nombre de la entrada >; base64, YWJjZGVmZw ==`. + * `toInternalURL` devuelve la ruta de la forma `file:///persistent/path/to/entry` (Firefox, IE). Cromo devuelve la ruta de acceso en el formulario `cdvfile://localhost/persistent/file`. + +### Rarezas de Chrome + + * Filesystem de Chrome no es inmediatamente después de evento ready dispositivo. Como solución temporal puede suscribirse al evento `filePluginIsReady`. Ejemplo: + +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` + +Puede utilizar la función `window.isFilePluginReadyRaised` para verificar si ya se provoca el evento. -window.requestFileSystem temporal y persistente filesystem cuotas no están limitadas en cromo. -Para aumentar el almacenamiento persistente en cromo necesitas llamar el método `window.initPersistentFileSystem`. Cuota de almacenamiento persistente es de 5 MB por defecto. -Chrome requiere `--permitir-archivo-acceso-de-archivos` ejecutar argumento al soporte API mediante protocolo `file:///`. -`Archivo` objeto no cambiará si utilizas bandera `{create:true}` cuando una `entrada` de existente. -eventos `cancelable` propiedad está establecida en true en cromo. Esto es contrario a la [Especificación](http://dev.w3.org/2009/dap/file-system/file-writer.html). -función de `toURL` en Chrome devuelve `filesystem:`-prefijo camino dependiendo de host de la aplicación. Por ejemplo, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -resultado de la función de `toURL` no contiene barra en caso de entrada en el directorio. Cromo resuelve directorios con urls slash-siguió correctamente sin embargo. -método `resolveLocalFileSystemURL` requiere la entrantes `url` que tienen prefijo `filesystem`. Por ejemplo, el parámetro de `url` para `resolveLocalFileSystemURL` debería estar en la forma `filesystem:file:///persistent/somefile.txt` en comparación con la forma `file:///persistent/somefile.txt` en Android. -Obsoleto `toNativeURL` función no es compatible y no tiene un trozo. -función de `setMetadata` no es indicada en las especificaciones y no admite. -INVALID_MODIFICATION_ERR (código: 9) se lanza en lugar de SYNTAX_ERR(code: 8) a petición de un sistema de ficheros inexistentes. -INVALID_MODIFICATION_ERR (código: 9) se lanza en vez de PATH_EXISTS_ERR(code: 12) en intentar exclusivamente crear un archivo o directorio, que ya existe. -INVALID_MODIFICATION_ERR (código: 9) se lanza en lugar de NO_MODIFICATION_ALLOWED_ERR(code: 6) para tratar de llamar a removeRecursively en el sistema de archivos raíz. -INVALID_MODIFICATION_ERR (código: 9) se lanza en vez de NOT_FOUND_ERR(code: 1) en tratar de moveTo directorio que no existe. + +### Impl base IndexedDB rarezas (IE y Firefox) + + * `.` y `..` no son compatibles. + * IE no soporta `file:///`-modo; modo alojado sólo es compatible (http://localhost:xxxx). + * Tamaño del sistema de archivos de Firefox no es limitada pero cada extensión de 50 MB solicitará un permiso de usuario. IE10 permite hasta 10mb de combinados AppCache y IndexedDB utilizados en la implementación del sistema de ficheros sin preguntar, cuando llegas a ese nivel que se le preguntará si desea permitir que ser aumentada hasta un máximo de 250 mb por sitio. Para que `size` parámetro para la función `requestFileSystem` no afecta sistema de ficheros en Firefox y IE. + * la función `readAsBinaryString` no se indica en las especificaciones y no compatible con IE y no tiene un trozo. + * `file.type` siempre es null. + * No debe crear entrada utilizando DirectoryEntry resultado de devolución de llamada de instancia que fue borrado. De lo contrario, obtendrá una entrada' colgar'. + * Antes de que se puede leer un archivo, el cual fue escrito sólo que necesitas una nueva instancia de este archivo. + * la función `setMetadata`, que no es indicada en las especificaciones soporta sólo el cambio de campo `modificationTime`. + * `copyTo` y `moveTo` funciones no son compatibles con directorios. + * Metadatos de directorios no es compatible. + * Tanto Entry.remove y directoryEntry.removeRecursively no fallan al retirar no vacía directorios - directorios de ser eliminados se limpian junto con contenido en su lugar. + * `abort` y `truncate` las funciones no son compatibles. + * eventos de progreso no están despedidos. Por ejemplo, este controlador no ejecutará: + +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## Actualización de notas + +En v1.0.0 de este plugin, han cambiado las estructuras `FileEntry` y `DirectoryEntry`, para estar más acorde con las especificaciones publicadas. + +Versiones anteriores (pre-1.0.0) del plugin almacenan el dispositivo-absoluto-archivo-ubicación en la propiedad `fullPath` de objetos de `entrada`. Estos caminos típicamente parecería + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Estas rutas también fueron devueltos por el método `toURL()` de los objetos de `entrada`. + +Con v1.0.0, el atributo `fullPath` es la ruta del archivo, *relativo a la raíz del sistema de archivos HTML*. Así, los caminos más arriba sería ahora ambos ser representado por un objeto `FileEntry` con un `fullPath` de + + /path/to/file + + +Si su aplicación funciona con dispositivo-absoluto-caminos, y previamente obtenido esos caminos a través de la propiedad `fullPath` de objetos de `Entry`, deberá actualizar el código para utilizar `entry.toURL()` en su lugar. + +Para atrás compatibilidad, el método `resolveLocalFileSystemURL()` a aceptar un dispositivo-absoluto-trayectoria y devolverá un objeto de `Entry` correspondiente que, mientras exista ese archivo dentro de los sistemas de ficheros `TEMPORARY` o la `PERSISTENT`. + +Esto ha sido particularmente un problema con el plugin de transferencia de archivos, que anteriormente utilizado dispositivo-absoluto-caminos (y todavía puede aceptarlas). Ha sido actualizado para funcionar correctamente con sistema de ficheros URLs, para reemplazar `entry.fullPath` con `entry.toURL()` debe resolver cualquier problema conseguir ese plugin para trabajar con archivos en el dispositivo. + +En v1.1.0 el valor devuelto por `toURL()` fue cambiado (consulte \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) para devolver una dirección URL absoluta 'file://'. siempre que sea posible. Para asegurar una ' cdvfile:'-URL ahora puede utilizar `toInternalURL()`. Este método devolverá ahora filesystem URLs de la forma + + cdvfile://localhost/persistent/path/to/file + + +que puede utilizarse para identificar el archivo únicamente. + +## Lista de códigos de Error y significados + +Cuando se produce un error, uno de los siguientes códigos se utilizará. + +| Código | Constante | +| ------:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Configurando el Plugin (opcional) + +El conjunto de los sistemas de ficheros disponibles puede ser configurado por plataforma. Tanto iOS y Android reconocen un etiqueta en el `archivo config.xml` que nombra a los sistemas de archivos para ser instalado. De forma predeterminada, se activan todas las raíces del sistema de archivos. + + + + + +### Android + + * `files`: directorio de almacenamiento de archivo interno de la aplicación + * `files-external`: directorio de almacenamiento de archivo externo de la aplicación + * `sdcard`: el directorio de almacenamiento de archivo externo global (esta es la raíz de la tarjeta SD, si uno está instalado). Debe tener el permiso de `android.permission.WRITE_EXTERNAL_STORAGE` a usar esto. + * `cache`: directorio de memoria caché interna de la aplicación + * `cache-external`: directorio de caché externo de la aplicación + * `root`: el sistema de archivos de todo el dispositivo + +Android también es compatible con un sistema de archivos especial llamado "documents", que representa un subdirectorio "/Documents/" dentro del sistema de archivos "archivos". + +### iOS + + * `library`: directorio de bibliotecas de la aplicación + * `documents`: directorio de documentos de la aplicación + * `cache`: directorio de caché de la aplicación + * `bundle`: paquete de la aplicación; la ubicación de la aplicación en sí mismo en el disco (sólo lectura) + * `root`: el sistema de archivos de todo el dispositivo + +De forma predeterminada, los directorios de documentos y la biblioteca pueden ser sincronizados con iCloud. También puede solicitar dos sistemas adicionales, `library-nosync` y `documents-nosync`, que representan un directorio especial no sincronizados dentro de la `/Library` o sistema de ficheros `/Documents`. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/es/index.md b/mobile/plugins/cordova-plugin-file/doc/es/index.md new file mode 100644 index 0000000..a9c0264 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/es/index.md @@ -0,0 +1,336 @@ + + +# cordova-plugin-file + +Este plugin implementa una API de archivo que permite acceso de lectura/escritura a los archivos que residen en el dispositivo. + +Este plugin se basa en varias especificaciones, incluyendo: el HTML5 archivo API + +Los directorios (ahora extinto) y sistema de extensiones más recientes: aunque la mayor parte del código del plugin fue escrito cuando una especificación anterior era actual: + +También implementa la especificación de FileWriter: + +Para el uso, por favor, consulte 'HTML5 Rocks excelente [FileSystem artículo.][1] + + [1]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +Para tener una visión general de otras opciones de almacenamiento, consulte [Guía de almacenamiento Cordova][2]. + + [2]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +Este plugin define global `cordova.file` objeto. + +Aunque en el ámbito global, no estará disponible hasta después de la `deviceready` evento. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## Instalación + + cordova plugin add cordova-plugin-file + + +## Plataformas soportadas + +* Amazon fire OS +* Android +* BlackBerry 10 +* Firefox OS +* iOS +* Windows Phone 7 y 8 * +* Windows 8 * +* Explorador + +* *No son compatibles con estas plataformas `FileReader.readAsArrayBuffer` ni `FileWriter.write(blob)` .* + +## Donde almacenar los archivos + +A partir de v1.2.0, URLs a directorios de sistema de archivos importantes son proporcionadas. Cada dirección URL está en la forma *file:///path/to/spot/*y se puede convertir en un `DirectoryEntry` usando`window.resolveLocalFileSystemURL()`. + +* `cordova.file.applicationDirectory`-Directorio Read-only donde está instalada la aplicación. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.applicationStorageDirectory`-Directorio del entorno limitado de la aplicación; en iOS esta ubicación es de sólo lectura (pero subdirectorios específicos [como `/Documents` ] son de lectura y escritura). Todos los datos contenidos dentro es privado para la aplicación. ( *iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.dataDirectory`-Almacenamiento de datos persistente y privadas dentro de entorno limitado de la aplicación utilizando la memoria interna (en Android, si necesitas usar memoria externa, use `.externalDataDirectory` ). En iOS, este directorio no está sincronizado con iCloud (utilice `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.cacheDirectory`-Directorio para los archivos de datos almacenados en caché o los archivos que su aplicación puede volver a crear fácilmente. El sistema operativo puede borrar estos archivos cuando el dispositivo se agota en almacenamiento de información, sin embargo, aplicaciones no deben confiar en el sistema operativo para eliminar los archivos de aquí. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.externalApplicationStorageDirectory`-Espacio aplicación de almacenamiento externo. (*Android*) + +* `cordova.file.externalDataDirectory`¿Dónde poner los archivos de datos específicos de la aplicación de almacenamiento externo. (*Android*) + +* `cordova.file.externalCacheDirectory`-Caché aplicación de almacenamiento externo. (*Android*) + +* `cordova.file.externalRootDirectory`-Raíz de almacenamiento externo (tarjeta SD). (*Android*, *BlackBerry 10*) + +* `cordova.file.tempDirectory`-Directorio temporal que puede borrar el sistema operativo en sí. No confíe en el sistema operativo para borrar este directorio; su aplicación siempre debe eliminar archivos según corresponda. (*iOS*) + +* `cordova.file.syncedDataDirectory`-Contiene los archivos de la aplicación específica que deben ser sincronizados (e.g. a iCloud). (*iOS*) + +* `cordova.file.documentsDirectory`-Archivos privados a la aplicación, pero que son significativos para otra aplicación (por ejemplo archivos de Office). (*iOS*) + +* `cordova.file.sharedDirectory`-Archivos disponibles globalmente para todas las aplicaciones (*BlackBerry 10*) + +## Diseños de sistema de archivo + +Aunque técnicamente un detalle de la implementación, puede ser muy útil saber cómo la `cordova.file.*` mapa de propiedades en trazados físicos en un dispositivo real. + +### iOS diseño de sistema de archivo + +| Ruta de dispositivo | `Cordova.file.*` | `iosExtraFileSystems` | ¿r/w? | ¿persistente? | OS despeja | sincronización | privado | +|:-------------------------------------------- |:--------------------------- |:--------------------- |:-----:|:-------------:|:----------:|:--------------:|:-------:| +| `/ var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N / A | N / A | N / A | Sí | +|    `appname.app/` | applicationDirectory | Bundle | r | N / A | N / A | N / A | Sí | +|       `www/` | - | - | r | N / A | N / A | N / A | Sí | +|    `Documents/` | documentsDirectory | documentos | r/w | Sí | No | Sí | Sí | +|       `NoCloud/` | - | documentos-nosync | r/w | Sí | No | No | Sí | +|    `Library` | - | Biblioteca | r/w | Sí | No | ¿Sí? | Sí | +|       `NoCloud/` | dataDirectory | Biblioteca-nosync | r/w | Sí | No | No | Sí | +|       `Cloud/` | syncedDataDirectory | - | r/w | Sí | No | Sí | Sí | +|       `Caches/` | cacheDirectory | caché | r/w | Sí * | Si * * *| | No | Sí | +|    `tmp/` | tempDirectory | - | r/w | No * * | Si * * *| | No | Sí | + +* Archivos persisten a través de la aplicación se reinicia y actualizaciones, pero este directorio puede ser despejó cuando el OS desea. Su aplicación debe ser capaz de recrear cualquier contenido que puede ser eliminado. + +* * Archivos pueden persistir a través de la aplicación se reinicia, pero no confiar en este comportamiento. Los archivos no se garantizan que persisten a través de actualizaciones. Su aplicación debe eliminar los archivos de este directorio cuando es aplicable, como el sistema operativo no garantiza cuando (o incluso si) estos archivos se quitan. + +* * *| OS la puede borrar el contenido de este directorio cuando se siente que es necesario, pero no dependen de éste. Debe borrar este directorio según sea apropiado para su aplicación. + +### Disposición del sistema Android File + +| Ruta de dispositivo | `Cordova.file.*` | `AndroidExtraFileSystems` | ¿r/w? | ¿persistente? | OS despeja | privado | +|:----------------------------------------- |:----------------------------------- |:------------------------- |:-----:|:-------------:|:----------:|:-------:| +| `File:///android_asset/` | applicationDirectory | | r | N / A | N / A | Sí | +| `/Data/data/< id de aplicación > /` | applicationStorageDirectory | - | r/w | N / A | N / A | Sí | +|    `cache` | cacheDirectory | caché | r/w | Sí | Sí * | Sí | +|    `files` | dataDirectory | archivos | r/w | Sí | No | Sí | +|       `Documents` | | documentos | r/w | Sí | No | Sí | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | Sí | No | No | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Sí | No | No | +|       `cache` | externalCacheDirectry | caché-externo | r/w | Sí | No * * | No | +|       `files` | externalDataDirectory | archivos externos | r/w | Sí | No | No | + +* El sistema operativo puede eliminar periódicamente este directorio, pero no dependen de este comportamiento. Borrar el contenido de este directorio según sea apropiado para su aplicación. El contenido de este directorio debe un usuario purga la caché manualmente, se eliminan. + +* * El sistema operativo no borra este directorio automáticamente; Usted es responsable de administrar el contenido mismo. Deberá el usuario purga la caché manualmente, se extraen los contenidos del directorio. + +**Nota**: Si no se puede montar de almacenamiento externo, el `cordova.file.external*` Propiedades`null`. + +### Disposición del sistema blackBerry 10 archivo + +| Ruta de dispositivo | `Cordova.file.*` | ¿r/w? | ¿persistente? | OS despeja | privado | +|:------------------------------------------------------------- |:--------------------------- |:-----:|:-------------:|:----------:|:-------:| +| `File:///accounts/1000/AppData/ < id de aplicación > /` | applicationStorageDirectory | r | N / A | N / A | Sí | +|    `app/native` | applicationDirectory | r | N / A | N / A | Sí | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | No | Sí | Sí | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Sí | No | Sí | +| `File:///accounts/1000/Removable/sdcard` | externalRemovableDirectory | r/w | Sí | No | No | +| `File:///accounts/1000/shared` | sharedDirectory | r/w | Sí | No | No | + +*Nota*: cuando se implementa la aplicación al trabajo de perímetro, todos los caminos son relativos a /accounts/1000-enterprise. + +## Rarezas Android + +### Ubicación de almacenamiento persistente Android + +Hay múltiples ubicaciones válidas para almacenar archivos persistentes en un dispositivo Android. Vea [esta página][3] para una extensa discusión de las distintas posibilidades. + + [3]: http://developer.android.com/guide/topics/data/data-storage.html + +Las versiones anteriores del plugin elegiría la ubicación de los archivos temporales y persistentes en el arranque, basado en si el dispositivo afirmó que fue montado en la tarjeta SD (o partición de almacenamiento equivalente). Si fue montada en la tarjeta SD, o una partición de gran almacenamiento interno estaba disponible (como en dispositivos de Nexus,) y luego los archivos persistentes se almacenaría en la raíz de ese espacio. Esto significaba que todas las apps Cordova podían ver todos los archivos disponibles en la tarjeta. + +Si la tarjeta SD no estaba disponible, entonces versiones anteriores podría almacenar datos debajo de `/data/data/` , que aísla las apps del otro, pero puede todavía causa datos para ser compartido entre los usuarios. + +Ahora es posible elegir si desea almacenar archivos en la ubicación de almacenamiento del archivo interno, o usando la lógica anterior, con una preferencia en de la aplicación `config.xml` archivo. Para ello, añada una de estas dos líneas a `config.xml` : + + < nombre de preferencia = "AndroidPersistentFileLocation" value = "Internal" / >< nombre de preferencia = "AndroidPersistentFileLocation" value = "Compatibilidad" / > + + +Sin esta línea, se utilizará el archivo plugin `Compatibility` como valor predeterminado. Si una etiqueta de preferencia está presente y no es uno de estos valores, no se iniciará la aplicación. + +Si su solicitud se ha enviado previamente a los usuarios, usando un mayor (1.0 pre) versión de este plugin y archivos almacenados en el sistema de ficheros persistente, entonces debería establecer la preferencia en `Compatibility` . Cambiar la ubicación para "Internal" significa que los usuarios existentes que actualización su aplicación pueden ser incapaces de acceder a sus archivos previamente almacenadas, dependiendo de su dispositivo. + +Si su solicitud es nuevo, o nunca antes ha almacenado archivos en el sistema de ficheros persistente, entonces el `Internal` generalmente se recomienda el ajuste. + +## iOS rarezas + +* `cordova.file.applicationStorageDirectory`es de sólo lectura; intentar almacenar archivos en el directorio raíz fallará. Utilice uno de los `cordova.file.*` las propiedades definidas para iOS (sólo `applicationDirectory` y `applicationStorageDirectory` son de sólo lectura). +* `FileReader.readAsText(blob, encoding)` + * El `encoding` no se admite el parámetro, y codificación UTF-8 es siempre en efecto. + +### iOS ubicación de almacenamiento persistente + +Hay dos ubicaciones válidas para almacenar archivos persistentes en un dispositivo iOS: el directorio de documentos y el directorio de biblioteca. Las versiones anteriores del plugin sólo almacenan archivos persistentes en el directorio de documentos. Esto tenía el efecto secundario de todos los archivos de la aplicación haciendo visible en iTunes, que era a menudo involuntarios, especialmente para aplicaciones que manejan gran cantidad de archivos pequeños, en lugar de producir documentos completos para la exportación, que es la finalidad del directorio. + +Ahora es posible elegir si desea almacenar archivos en los documentos o directorio de bibliotecas, con preferencia en de la aplicación `config.xml` archivo. Para ello, añada una de estas dos líneas a `config.xml` : + + + + + + +Sin esta línea, se utilizará el archivo plugin `Compatibility` como valor predeterminado. Si una etiqueta de preferencia está presente y no es uno de estos valores, no se iniciará la aplicación. + +Si su solicitud se ha enviado previamente a los usuarios, usando un mayor (1.0 pre) versión de este plugin y archivos almacenados en el sistema de ficheros persistente, entonces debería establecer la preferencia en `Compatibility` . Cambiar la ubicación de `Library` significa que los usuarios existentes que actualización su aplicación sería incapaces de acceder a sus archivos previamente almacenadas. + +Si su solicitud es nuevo, o nunca antes ha almacenado archivos en el sistema de ficheros persistente, entonces el `Library` generalmente se recomienda el ajuste. + +## Firefox OS rarezas + +La API de sistema de archivo de forma nativa no es compatible con Firefox OS y se implementa como una cuña en la parte superior indexedDB. + +* No falla cuando eliminar directorios no vacía +* No admite metadatos para directorios +* Los métodos `copyTo` y `moveTo` no son compatibles con directorios + +Se admiten las siguientes rutas de datos: * `applicationDirectory` -usa `xhr` para obtener los archivos locales que están envasados con la aplicación. * `dataDirectory` - Para archivos de datos específicos de aplicación persistente. * `cacheDirectory` -En caché archivos que deben sobrevivir se reinicia la aplicación (aplicaciones no deben confiar en el sistema operativo para eliminar archivos aquí). + +## Navegador rarezas + +### Rarezas y observaciones comunes + +* Cada navegador utiliza su propio sistema de ficheros un espacio aislado. IE y Firefox utilizan IndexedDB como base. Todos los navegadores utilizan diagonal como separador de directorio en un camino. +* Las entradas de directorio deben crearse sucesivamente. Por ejemplo, la llamada `fs.root.getDirectory (' dir1/dir2 ', {create:true}, successCallback, errorCallback)` se producirá un error si no existiera dir1. +* El plugin solicita permiso de usuario para usar almacenamiento persistente en el primer comienzo de la aplicación. +* Plugin soporta `cdvfile://localhost` (recursos locales) solamente. Es decir, no se admiten los recursos externos vía `cdvfile`. +* El plugin no sigue ["Archivo sistema API 8.3 nombrando restricciones"][4]. +* BLOB y archivo ' `close` la función no es compatible. +* `FileSaver` y `BlobBuilder` no son compatibles con este plugin y no tengo recibos. +* El plugin no es compatible con `requestAllFileSystems`. Esta función también está desaparecida en las especificaciones. +* No se quitarán las entradas de directorio Si utilizas `create: true` bandera de directorio existente. +* No se admiten archivos creados mediante el constructor. Debe utilizar método entry.file en su lugar. +* Cada navegador utiliza su propia forma de blob URL referencias. +* se admite la función `readAsDataURL`, pero el mediatype en cromo depende de la extensión de nombre de entrada, mediatype en IE siempre está vacío (que es lo mismo como `plain-text` según la especificación), el mediatype en Firefox siempre es `application/octet-stream`. Por ejemplo, si el contenido es `abcdefg` entonces Firefox devuelve `datos: aplicación / octet-stream; base64, YWJjZGVmZw ==`, es decir devuelve `datos:; base64, YWJjZGVmZw ==`, cromo devuelve `datos: < mediatype dependiendo de la extensión de nombre de la entrada >; base64, YWJjZGVmZw ==`. +* `toInternalURL` devuelve la ruta de la forma `file:///persistent/path/to/entry` (Firefox, IE). Cromo devuelve la ruta de acceso en el formulario `cdvfile://localhost/persistent/file`. + + [4]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions + +### Rarezas de Chrome + +* Filesystem de Chrome no es inmediatamente después de evento ready dispositivo. Como solución temporal puede suscribirse al evento `filePluginIsReady`. Ejemplo: + + javascript + window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); + + +Puede utilizar la función `window.isFilePluginReadyRaised` para verificar si ya se provoca el evento. -window.requestFileSystem temporal y persistente filesystem cuotas no están limitadas en cromo. -Para aumentar el almacenamiento persistente en cromo necesitas llamar el método `window.initPersistentFileSystem`. Cuota de almacenamiento persistente es de 5 MB por defecto. -Chrome requiere `--permitir-archivo-acceso-de-archivos` ejecutar argumento al soporte API mediante protocolo `file:///`. -`Archivo` objeto no cambiará si utilizas bandera `{create:true}` cuando una `entrada` de existente. -eventos `cancelable` propiedad está establecida en true en cromo. Esto es contrario a la [Especificación][5]. -función de `toURL` en Chrome devuelve `filesystem:`-prefijo camino dependiendo de host de la aplicación. Por ejemplo, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -resultado de la función de `toURL` no contiene barra en caso de entrada en el directorio. Cromo resuelve directorios con urls slash-siguió correctamente sin embargo. -método `resolveLocalFileSystemURL` requiere la entrantes `url` que tienen prefijo `filesystem`. Por ejemplo, el parámetro de `url` para `resolveLocalFileSystemURL` debería estar en la forma `filesystem:file:///persistent/somefile.txt` en comparación con la forma `file:///persistent/somefile.txt` en Android. -Obsoleto `toNativeURL` función no es compatible y no tiene un trozo. -función de `setMetadata` no es indicada en las especificaciones y no admite. -INVALID_MODIFICATION_ERR (código: 9) se lanza en lugar de SYNTAX_ERR(code: 8) a petición de un sistema de ficheros inexistentes. -INVALID_MODIFICATION_ERR (código: 9) se lanza en vez de PATH_EXISTS_ERR(code: 12) en intentar exclusivamente crear un archivo o directorio, que ya existe. -INVALID_MODIFICATION_ERR (código: 9) se lanza en lugar de NO_MODIFICATION_ALLOWED_ERR(code: 6) para tratar de llamar a removeRecursively en el sistema de archivos raíz. -INVALID_MODIFICATION_ERR (código: 9) se lanza en vez de NOT_FOUND_ERR(code: 1) en tratar de moveTo directorio que no existe. + + [5]: http://dev.w3.org/2009/dap/file-system/file-writer.html + +### Impl base IndexedDB rarezas (IE y Firefox) + +* `.` y `..` no son compatibles. +* IE no soporta `file:///`-modo; modo alojado sólo es compatible (http://localhost:xxxx). +* Tamaño del sistema de archivos de Firefox no es limitada pero cada extensión de 50 MB solicitará un permiso de usuario. IE10 permite hasta 10mb de combinados AppCache y IndexedDB utilizados en la implementación del sistema de ficheros sin preguntar, cuando llegas a ese nivel que se le preguntará si desea permitir que ser aumentada hasta un máximo de 250 mb por sitio. Para que `size` parámetro para la función `requestFileSystem` no afecta sistema de ficheros en Firefox y IE. +* la función `readAsBinaryString` no se indica en las especificaciones y no compatible con IE y no tiene un trozo. +* `file.type` siempre es null. +* No debe crear entrada utilizando DirectoryEntry resultado de devolución de llamada de instancia que fue borrado. De lo contrario, obtendrá una entrada' colgar'. +* Antes de que se puede leer un archivo, el cual fue escrito sólo que necesitas una nueva instancia de este archivo. +* la función `setMetadata`, que no es indicada en las especificaciones soporta sólo el cambio de campo `modificationTime`. +* `copyTo` y `moveTo` funciones no son compatibles con directorios. +* Metadatos de directorios no es compatible. +* Tanto Entry.remove y directoryEntry.removeRecursively no fallan al retirar no vacía directorios - directorios de ser eliminados se limpian junto con contenido en su lugar. +* `abort` y `truncate` las funciones no son compatibles. +* eventos de progreso no están despedidos. Por ejemplo, este controlador no ejecutará: + + javascript + writer.onprogress = function() { /*commands*/ }; + + +## Actualización de notas + +En v1.0.0 de este plugin, han cambiado las estructuras `FileEntry` y `DirectoryEntry`, para estar más acorde con las especificaciones publicadas. + +Versiones anteriores (pre-1.0.0) del plugin almacenan el dispositivo-absoluto-archivo-ubicación en la propiedad `fullPath` de objetos de `entrada`. Estos caminos típicamente parecería + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Estas rutas también fueron devueltos por el método `toURL()` de los objetos de `entrada`. + +Con v1.0.0, el atributo `fullPath` es la ruta del archivo, *relativo a la raíz del sistema de archivos HTML*. Así, los caminos más arriba sería ahora ambos ser representado por un objeto `FileEntry` con un `fullPath` de + + /path/to/file + + +Si su aplicación funciona con dispositivo-absoluto-caminos, y previamente obtenido esos caminos a través de la propiedad `fullPath` de objetos de `Entry`, deberá actualizar el código para utilizar `entry.toURL()` en su lugar. + +Para atrás compatibilidad, el método `resolveLocalFileSystemURL()` a aceptar un dispositivo-absoluto-trayectoria y devolverá un objeto de `Entry` correspondiente que, mientras exista ese archivo dentro de los sistemas de ficheros `TEMPORARY` o la `PERSISTENT`. + +Esto ha sido particularmente un problema con el plugin de transferencia de archivos, que anteriormente utilizado dispositivo-absoluto-caminos (y todavía puede aceptarlas). Ha sido actualizado para funcionar correctamente con sistema de ficheros URLs, para reemplazar `entry.fullPath` con `entry.toURL()` debe resolver cualquier problema conseguir ese plugin para trabajar con archivos en el dispositivo. + +En v1.1.0 el valor devuelto por `toURL()` fue cambiado (consulte \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) para devolver una dirección URL absoluta 'file://'. siempre que sea posible. Para asegurar una ' cdvfile:'-URL ahora puede utilizar `toInternalURL()`. Este método devolverá ahora filesystem URLs de la forma + + cdvfile://localhost/persistent/path/to/file + + +que puede utilizarse para identificar el archivo únicamente. + +## Lista de códigos de Error y significados + +Cuando se produce un error, uno de los siguientes códigos se utilizará. + +| Código | Constante | +| ------:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Configurando el Plugin (opcional) + +El conjunto de los sistemas de ficheros disponibles puede ser configurado por plataforma. Tanto iOS y Android reconocen un etiqueta en el `archivo config.xml` que nombra a los sistemas de archivos para ser instalado. De forma predeterminada, se activan todas las raíces del sistema de archivos. + + + + + +### Android + +* `files`: directorio de almacenamiento de archivo interno de la aplicación +* `files-external`: directorio de almacenamiento de archivo externo de la aplicación +* `sdcard`: el directorio de almacenamiento de archivo externo global (esta es la raíz de la tarjeta SD, si uno está instalado). Debe tener el permiso de `android.permission.WRITE_EXTERNAL_STORAGE` a usar esto. +* `cache`: directorio de memoria caché interna de la aplicación +* `cache-external`: directorio de caché externo de la aplicación +* `root`: el sistema de archivos de todo el dispositivo + +Android también es compatible con un sistema de archivos especial llamado "documents", que representa un subdirectorio "/Documents/" dentro del sistema de archivos "archivos". + +### iOS + +* `library`: directorio de bibliotecas de la aplicación +* `documents`: directorio de documentos de la aplicación +* `cache`: directorio de caché de la aplicación +* `bundle`: paquete de la aplicación; la ubicación de la aplicación en sí mismo en el disco (sólo lectura) +* `root`: el sistema de archivos de todo el dispositivo + +De forma predeterminada, los directorios de documentos y la biblioteca pueden ser sincronizados con iCloud. También puede solicitar dos sistemas adicionales, `library-nosync` y `documents-nosync`, que representan un directorio especial no sincronizados dentro de la `/Library` o sistema de ficheros `/Documents`. diff --git a/mobile/plugins/cordova-plugin-file/doc/es/plugins.md b/mobile/plugins/cordova-plugin-file/doc/es/plugins.md new file mode 100644 index 0000000..dace368 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/es/plugins.md @@ -0,0 +1,101 @@ + + +# Notas para los desarrolladores del plugin + +Estas notas están pensadas principalmente para desarrolladores de Android y el iOS que quieran escribir plugins que interfaz con el sistema de ficheros usando el plugin del archivo. + +## Trabajar con URLs de sistema de archivo de Córdoba + +Desde la versión 1.0.0, este plugin ha utilizado las direcciones URL con un `cdvfile` plan para todas las comunicaciones sobre el puente, en lugar de exponer rutas de sistema de archivos de dispositivos raw para JavaScript. + +En el lado de JavaScript, esto significa que los objetos FileEntry y DirectoryEntry tienen un atributo fullPath que es relativo a la raíz del sistema de archivos HTML. Si JavaScript API de tu plugin acepta un objeto FileEntry o DirectoryEntry, usted debe llamar a `.toURL()` en ese objeto antes de pasar a través del puente al código nativo. + +### Conversión de cdvfile: / / URL al fileystem caminos + +Plugins que necesita escribir en el sistema de archivos puede convertir un archivo recibido sistema URL a una ubicación de sistema de archivos real. Hay varias formas de hacerlo, dependiendo de la plataforma nativa. + +Es importante recordar que no todos `cdvfile://` las direcciones URL son asignables a reales archivos en el dispositivo. Algunas URLs pueden referirse a activos en dispositivos que no están representadas por archivos, o incluso pueden hacer referencia a recursos remotos. Debido a estas posibilidades, plugins siempre debe comprobar si consiguen un resultado significativo cuando tratando de convertir las URL en trazados. + +#### Android + +En Android, el método más simple para convertir un `cdvfile://` URL a una ruta de sistema de archivos es utilizar `org.apache.cordova.CordovaResourceApi` . `CordovaResourceApi`tiene varios métodos que pueden manejar `cdvfile://` URL: + + webView es un miembro de la clase Plugin CordovaResourceApi resourceApi = webView.getResourceApi(); + + Obtener una URL file:/// representando este archivo en el dispositivo, / / o el mismo URL sin cambios si no se puede asignar a un archivo Uri fileURL = resourceApi.remapUri(Uri.parse(cdvfileURL)); + + +También es posible utilizar el plugin de archivos directamente: + + Import org.apache.cordova.file.FileUtils; + Import org.apache.cordova.file.FileSystem; + Import java.net.MalformedURLException; + + Obtener el archivo plugin desde el administrador de plugin FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + Dada una URL, haz un camino para tratar de {camino de cadena = filePlugin.filesystemPathForURL(cdvfileURL);} catch (DD e) {/ / el sistema de archivos url no reconocida} + + +Para convertir de una ruta a un `cdvfile://` URL: + + Import org.apache.cordova.file.LocalFilesystemURL; + + Obtener un objeto LocalFilesystemURL para una ruta, / / o null si no se puede representar como una dirección URL cdvfile. + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path); + Obtener la representación string de la URL objeto String cdvfileURL = url.toString(); + + +Si tu plugin crea un archivo y desea devolver un objeto FileEntry para él, usar el plugin de archivos: + + Devolver una estructura JSON adecuado para volver a JavaScript, / / o null si este archivo no es representable como una dirección URL cdvfile. + JSONObject entrada = filePlugin.getEntryForFile(file); + + +#### iOS + +Cordova en iOS no utiliza la misma `CordovaResourceApi` concepto como Android. En iOS, debe usar el archivo plugin para convertir las direcciones URL y rutas de sistema de archivos. + + Obtener un objeto URL CDVFilesystem de una URL string CDVFilesystemURL * url = [CDVFilesystemURL fileSystemURLWithString:cdvfileURL]; + Obtener una ruta de acceso para el objeto URL, o nil si no puede ser asignado a una ruta de archivo NSString * = [filePlugin filesystemPathForURL:url]; + + + Obtener un objeto URL CDVFilesystem para una ruta, o / / nula si no se puede representar como una dirección URL cdvfile. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + Obtener la representación string de la URL objetos NSString * cdvfileURL = [enlace absoluteString]; + + +Si tu plugin crea un archivo y desea devolver un objeto FileEntry para él, usar el plugin de archivos: + + Obtener un objeto URL CDVFilesystem para una ruta, o / / nula si no se puede representar como una dirección URL cdvfile. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + Conseguir una estructura para volver a JavaScript NSDictionary * entrada = [filePlugin makeEntryForLocalURL:url] + + +#### JavaScript + +En JavaScript, para obtener un `cdvfile://` dirección URL de un objeto FileEntry o DirectoryEntry, simplemente llame al `.toURL()` en él: + + var cdvfileURL = entry.toURL(); + + +En manipuladores de la respuesta del plugin, para convertir de una estructura FileEntry devuelta a un objeto real de la entrada, su código de controlador debe importar el archivo plugin y crear un nuevo objeto: + + crear apropiado objeto var ingreso; + Si (entryStruct.isDirectory) {entrada = new DirectoryEntry (entryStruct.name, entryStruct.fullPath, FileSystem(entryStruct.filesystemName)) nuevo;} else {entrada = nuevo FileEntry (entryStruct.name, entryStruct.fullPath, nuevo FileSystem(entryStruct.filesystemName));} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/fr/README.md b/mobile/plugins/cordova-plugin-file/doc/fr/README.md new file mode 100644 index 0000000..6296a84 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/fr/README.md @@ -0,0 +1,328 @@ + + +# cordova-plugin-file + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg)](https://travis-ci.org/apache/cordova-plugin-file) + +Ce plugin implémente une API de fichier permettant l'accès en lecture/écriture aux fichiers qui résident sur le périphérique. + +Ce plugin est basé sur plusieurs spécifications, y compris : l'API de fichier HTML5 + +Les répertoires (aujourd'hui disparue) et le système des extensions plus récentes : bien que la plupart du code du plugin a été écrit quand une technique antérieure était en vigueur : + +Il met également en œuvre la spécification FileWriter : + +Pour son utilisation, veuillez vous reporter au HTML5 Rocks' excellent [article de système de fichiers.](http://www.html5rocks.com/en/tutorials/file/filesystem/) + +Pour un aperçu des autres options de stockage, consultez [guide d'entreposage de Cordova](http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html). + +Ce plugin définit global `cordova.file` objet. + +Bien que dans la portée globale, il n'est pas disponible jusqu'après la `deviceready` événement. + + document.addEventListener (« deviceready », onDeviceReady, false) ; + function onDeviceReady() {console.log(cordova.file);} + + +## Installation + + cordova plugin add cordova-plugin-file + + +## Plates-formes supportées + + * Amazon Fire OS + * Android + * BlackBerry 10 + * Firefox OS + * iOS + * Windows Phone 7 et 8 * + * Windows 8 * + * Windows* + * Navigateur + +\* *These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`.* + +## Emplacement de stockage des fichiers + +À partir de v1.2.0, URL vers des répertoires de système de fichiers importants est fournis. Chaque URL est dans la forme *file:///path/to/spot/*et peut être converti en un `DirectoryEntry` à l'aide`window.resolveLocalFileSystemURL()`. + + * `cordova.file.applicationDirectory`-Lecture seule répertoire où l'application est installée. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.applicationStorageDirectory`-Répertoire racine du bac à sable de l'application ; cet endroit est en lecture seule sur iOS (mais les sous-répertoires spécifiques [comme `/Documents` ] sont en lecture / écriture). Toutes les données qu'il contient est privé de l'application. ( *iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.dataDirectory`-Stockage des données persistants et privés au sein de bac à sable de l'application à l'aide de la mémoire interne (sur Android, si vous avez besoin d'utiliser une mémoire externe, utilisez `.externalDataDirectory` ). Sur iOS, ce répertoire n'est pas synchronisé avec iCloud (utiliser `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.cacheDirectory`-Répertoire pour les fichiers de données en mémoire cache ou les fichiers que votre application peut recréer facilement. L'OS peut supprimer ces fichiers lorsque l'appareil faiblit sur stockage, néanmoins, les applications ne doivent pas compter sur l'OS pour supprimer les fichiers ici. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.externalApplicationStorageDirectory`-Espace l'application sur le stockage externe. (*Android*) + + * `cordova.file.externalDataDirectory`-Où placer les fichiers de données d'application spécifiques sur le stockage externe. (*Android*) + + * `cordova.file.externalCacheDirectory`-Cache de l'application sur le stockage externe. (*Android*) + + * `cordova.file.externalRootDirectory`-Racine de stockage externe (carte SD). (*Android*, *BlackBerry 10*) + + * `cordova.file.tempDirectory`-Répertoire temp que l'OS peut effacer à volonté. Ne comptez pas sur l'OS pour effacer ce répertoire ; votre application doit toujours supprimer les fichiers selon le cas. (*iOS*) + + * `cordova.file.syncedDataDirectory`-Contient des fichiers d'app spécifique qui doivent se synchroniser (par exemple à iCloud). (*iOS*) + + * `cordova.file.documentsDirectory`-Fichiers privés à l'app, mais qui sont significatives pour l'autre application (par exemple les fichiers Office). (*iOS*) + + * `cordova.file.sharedDirectory`-Fichiers disponibles globalement à toutes les applications (*BlackBerry 10*) + +## Structures de système de fichiers + +Bien que techniquement un détail d'implémentation, il peut être très utile de savoir comment les `cordova.file.*` carte de propriétés à des chemins d'accès physiques sur un périphérique réel. + +### iOS agencement de système de fichier + +| Chemin de l'unité | `Cordova.file.*` | `iosExtraFileSystems` | r/w ? | persistants ? | OS efface | Sync | privé | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:-----:|:-------------:|:-------------:|:-----:|:-----:| +| `/ var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N/A | N/A | N/A | Oui | +|    `appname.app/` | applicationDirectory | Bundle | r | N/A | N/A | N/A | Oui | +|       `www/` | - | - | r | N/A | N/A | N/A | Oui | +|    `Documents/` | documentsDirectory | documents | r/w | Oui | Non | Oui | Oui | +|       `NoCloud/` | - | documents-nosync | r/w | Oui | Non | Non | Oui | +|    `Library` | - | Bibliothèque | r/w | Oui | Non | Oui ? | Oui | +|       `NoCloud/` | dataDirectory | Bibliothèque-nosync | r/w | Oui | Non | Non | Oui | +|       `Cloud/` | syncedDataDirectory | - | r/w | Oui | Non | Oui | Oui | +|       `Caches/` | cacheDirectory | cache | r/w | Oui * | Oui**\* | Non | Oui | +|    `tmp/` | tempDirectory | - | r/w | Non** | Oui**\* | Non | Oui | + +\ * Fichiers persistent à travers l'application redémarre et mises à niveau, mais ce répertoire peut être effacé à chaque fois que le système d'exploitation désire. Votre application doit être en mesure de recréer tout contenu qui pourrait être supprimé. + +** Fichiers peuvent persister redémarrages de l'application, mais ne vous fiez pas ce comportement. Les fichiers ne sont pas garantis à persister dans l'ensemble de mises à jour. Votre application doit supprimer les fichiers de ce répertoire lorsqu'elle s'applique, comme le système d'exploitation ne garantit pas quand (ou même si) ces fichiers sont supprimés. + +**\ * Le système d'exploitation peut effacer le contenu de ce répertoire chaque fois qu'il se sent il est nécessaire, mais ne comptez pas là-dessus. Vous devez supprimer ce répertoire comme approprié pour votre application. + +### Agencement de système de fichiers Android + +| Chemin de l'unité | `Cordova.file.*` | `AndroidExtraFileSystems` | r/w ? | persistants ? | OS efface | privé | +|:------------------------------------------------ |:----------------------------------- |:------------------------- |:-----:|:-------------:|:---------:|:-----:| +| `file:///android_asset/` | applicationDirectory | | r | N/A | N/A | Oui | +| `/ données/data/app < id > /` | applicationStorageDirectory | - | r/w | N/A | N/A | Oui | +|    `cache` | cacheDirectory | cache | r/w | Oui | Oui\ * | Oui | +|    `files` | dataDirectory | fichiers | r/w | Oui | Non | Oui | +|       `Documents` | | documents | r/w | Oui | Non | Oui | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | Oui | Non | Non | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Oui | Non | Non | +|       `cache` | externalCacheDirectry | cache-externe | r/w | Oui | Non** | Non | +|       `files` | externalDataDirectory | fichiers externes | r/w | Oui | Non | Non | + +\ * L'OS peut effacer périodiquement ce répertoire, mais ne vous fiez pas ce comportement. Effacer le contenu de ce répertoire comme approprié pour votre application. Un utilisateur doit purger le cache manuellement, le contenu de ce répertoire est supprimé. + +** Le système d'exploitation n'efface pas ce répertoire automatiquement ; vous êtes chargé de gérer le contenu vous-même. L'utilisateur devrait purger le cache manuellement, le contenu du répertoire est supprimé. + +**Remarque**: si le stockage externe ne peut pas être monté, les `cordova.file.external*` sont des propriétés`null`. + +### Configuration du système blackBerry 10 fichier + +| Chemin de l'unité | `Cordova.file.*` | r/w ? | persistants ? | OS efface | privé | +|:----------------------------------------------------------- |:--------------------------- |:-----:|:-------------:|:---------:|:-----:| +| `file:///Accounts/1000/AppData/ < id app > /` | applicationStorageDirectory | r | N/A | N/A | Oui | +|    `app/native` | applicationDirectory | r | N/A | N/A | Oui | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | Non | Oui | Oui | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Oui | Non | Oui | +| `file:///Accounts/1000/Removable/sdcard` | externalRemovableDirectory | r/w | Oui | Non | Non | +| `file:///Accounts/1000/Shared` | sharedDirectory | r/w | Oui | Non | Non | + +*Remarque*: lorsque l'application est déployée dans le périmètre de travail, tous les chemins sont par rapport à /accounts/1000-enterprise. + +## Quirks Android + +### Emplacement de stockage persistant Android + +Il y a plusieurs emplacements valides pour stocker des fichiers persistants sur un appareil Android. Voir [cette page](http://developer.android.com/guide/topics/data/data-storage.html) pour une analyse approfondie des diverses possibilités. + +Les versions précédentes du plugin choisirait l'emplacement des fichiers temporaires et persistantes au démarrage, basé sur la question de savoir si le dispositif réclamé que la carte SD (ou une partition de stockage équivalent) a été montée. Si la carte SD a été montée, ou si une partition de stockage interne importante était disponible (comme sur les appareils Nexus,) puis les fichiers persistants seraient stockés dans la racine de cet espace. Cela signifie que toutes les apps de Cordova pouvaient voir tous les fichiers disponibles sur la carte. + +Si la carte SD n'était pas disponible, les versions précédentes pourraient stocker des données sous `/data/data/` , qui isole des apps de l'autre, mais peut encore cause données à partager entre les utilisateurs. + +Il est maintenant possible de choisir de stocker les fichiers dans l'emplacement de stockage de fichier interne, ou en utilisant la logique précédente, avec une préférence au sein de votre application `config.xml` fichier. Pour ce faire, ajoutez l'un de ces deux lignes de `config.xml` : + + < nom de l'option = « AndroidPersistentFileLocation » value = « Internal » / >< nom de préférence = « AndroidPersistentFileLocation » value = « Compatibilité » / > + + +Sans cette ligne, utilisera le fichier plugin `Compatibility` par défaut. Si une balise de préférence est présente et n'est pas une des valeurs suivantes, l'application ne démarrera pas. + +Si votre application a déjà été expédiée aux utilisateurs, en utilisant une ancienne (avant 1.0) version de ce plugin et dispose des fichiers stockés dans le système de fichiers persistant, alors vous devez définir la préférence au `Compatibility` . Commutation de l'emplacement « Internal » signifierait que les utilisateurs existants qui mettre à niveau leur application peuvent être impossible d'accéder à leurs fichiers déjà enregistrés, selon leur appareil. + +Si votre application est nouvelle ou a jamais précédemment stocké les fichiers dans le système de fichiers persistant, puis la `Internal` réglage est généralement recommandé. + +### Opérations récursives lent pour /android_asset + +Liste des répertoires actifs est vraiment lent sur Android. Vous pouvez accélérer il vers le haut, en ajoutant `src/android/build-extras.gradle` à la racine de votre projet android (requiert également cordova-android@4.0.0 ou supérieur). + +## Notes au sujet d'iOS + + * `cordova.file.applicationStorageDirectory`est en lecture seule ; tentative de stocker des fichiers dans le répertoire racine échoue. Utilisez l'une de l'autre `cordova.file.*` les propriétés définies pour iOS (seulement `applicationDirectory` et `applicationStorageDirectory` sont en lecture seule). + * `FileReader.readAsText(blob, encoding)` + * Le `encoding` paramètre n'est pas pris en charge, et le codage UTF-8 est toujours en vigueur. + +### emplacement de stockage persistant d'iOS + +Il y a deux emplacements valides pour stocker des fichiers persistants sur un appareil iOS : le répertoire de Documents et le répertoire de la bibliothèque. Les versions précédentes du plugin stockaient ne jamais fichiers persistants dans le répertoire de Documents. Cela a eu l'effet secondaire de rendre tous les fichiers de l'application visible dans iTunes, qui était souvent inattendus, en particulier pour les applications qui traitent beaucoup de petits fichiers, plutôt que de produire des documents complets destinés à l'exportation, qui est l'objectif visé par le répertoire. + +Il est maintenant possible de choisir de stocker les fichiers dans le répertoire de bibliothèque, avec une préférence au sein de votre application ou de documents `config.xml` fichier. Pour ce faire, ajoutez l'un de ces deux lignes de `config.xml` : + + < nom de l'option = « iosPersistentFileLocation » value = « Library » / >< nom de préférence = « iosPersistentFileLocation » value = « Compatibilité » / > + + +Sans cette ligne, utilisera le fichier plugin `Compatibility` par défaut. Si une balise de préférence est présente et n'est pas une des valeurs suivantes, l'application ne démarrera pas. + +Si votre application a déjà été expédiée aux utilisateurs, en utilisant une ancienne (avant 1.0) version de ce plugin et dispose des fichiers stockés dans le système de fichiers persistant, alors vous devez définir la préférence au `Compatibility` . Changer l'emplacement de `Library` voudrait dire que les utilisateurs existants qui mettre à niveau leur application serait incapables d'accéder à leurs fichiers déjà enregistrés. + +Si votre application est nouvelle ou a jamais précédemment stocké les fichiers dans le système de fichiers persistant, puis la `Library` réglage est généralement recommandé. + +## Firefox OS Quirks + +L'API de système de fichier n'est pas nativement pris en charge par Firefox OS et est implémentée comme une cale d'épaisseur sur le dessus d'indexedDB. + + * Ne manque pas lors de la suppression des répertoires non vide + * Ne supporte pas les métadonnées pour les répertoires + * Méthodes `copyTo` et `moveTo` ne prennent pas en charge les répertoires + +Les chemins de données suivants sont pris en charge: * `applicationDirectory` -utilise `xhr` pour obtenir des fichiers les qui sont emballées avec l'app. * `dataDirectory` - Pour les fichiers de données persistantes de app spécifique. * `cacheDirectory` -Mise en cache de fichiers qui doivent survivre les redémarrages de l'application (les applications ne doivent pas compter sur le système d'exploitation pour supprimer les fichiers ici). + +## Bizarreries navigateur + +### Commune de bizarreries et de remarques + + * Chaque navigateur utilise son propre système de fichiers en bac à sable. IE et Firefox utilisent IndexedDB comme base. Tous les navigateurs utilisent oblique comme séparateur de répertoire dans un chemin d'accès. + * Entrées d'annuaire doivent être créées successivement. Par exemple, l'appel `fs.root.getDirectory (' dir1/dir2 ', {create:true}, successCallback, errorCallback)` échouera si dir1 n'existait pas. + * Le plugin demande utilisateur l'autorisation d'utiliser le stockage persistant lors du premier démarrage d'application. + * Plugin supporte `cdvfile://localhost` (ressources locales) seulement. C'est-à-dire les ressources externes ne sont pas supportés par l'intermédiaire de `cdvfile`. + * Le plugin ne suit pas les ["Restrictions de nommage des fichiers système API 8.3"](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions). + * BLOB et le fichier "`close` la fonction n'est pas pris en charge. + * `FileSaver` et `BlobBuilder` ne sont pas pris en charge par ce plugin et n'ont stubs. + * Le plugin ne supporte pas les `requestAllFileSystems`. Cette fonction est également absent dans les cahier des charges. + * Inscriptions dans l'annuaire ne seront pas supprimées si vous utilisez `create: true` drapeau pour le répertoire existant. + * Fichiers créés via le constructeur ne sont pas pris en charge. Vous devez plutôt utiliser entry.file méthode. + * Chaque navigateur utilise sa propre forme de références URL blob. + * `readAsDataURL` fonction est prise en charge, mais le mediatype en Chrome dépend de l'extension entrée, mediatype dans IE est toujours vide (qui est le même que le `texte-plaine` selon la spécification), le mediatype dans Firefox est toujours `application/octet-stream`. Par exemple, si le contenu est `abcdefg` puis Firefox renvoie `données : application / octet-stream ; base64, YWJjZGVmZw ==`, c'est à dire les retours `données:; base64, YWJjZGVmZw ==`, retours de Chrome `données : < mediatype selon l'extension de nom d'entrée > ; base64, YWJjZGVmZw ==`. + * `toInternalURL` retourne le chemin d'accès dans le formulaire `file:///persistent/path/to/entry` (Firefox, IE). Chrome retourne le chemin d'accès dans le formulaire `cdvfile://localhost/persistent/file`. + +### Bizarreries de chrome + + * Chrome filesystem n'est pas prête immédiatement après l'événement ready périphérique. Pour contourner le problème, vous pouvez vous abonner à l'événement `filePluginIsReady`. Exemple : + +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` + +Vous pouvez utiliser la fonction `window.isFilePluginReadyRaised` pour vérifier si les événement était déjà déclenché. -quotas de window.requestFileSystem temporaire et permanent de système de fichiers ne sont pas limités en Chrome. -Pour augmenter le stockage persistant en Chrome, vous devez appeler la méthode `window.initPersistentFileSystem`. Quota de stockage persistant est 5 Mo par défaut. -Chrome nécessite `--permettre-fichier-accès-de-fichiers` exécuter l'argument au support API via le protocole `file:///`. -`Fichier` objet changera pas si vous utilisez le drapeau `{create:true}` lors du passage d'une `entrée` existante. -événements `annulables` propriété a la valeur true dans Chrome. Il s'agit à l'encontre de la [spécification](http://dev.w3.org/2009/dap/file-system/file-writer.html). -`toURL` renvoie à Chrome `système de fichiers :`-préfixe de chemin d'accès selon l'application hôte. Par exemple, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -résultat de la fonction `toURL` ne contient-elle pas de barre oblique dans le cas d'entrée d'annuaire. Chrome résout répertoires avec barre oblique-trainés URL correctement cependant. -`resolveLocalFileSystemURL` méthode nécessite l' entrant `url` préfixe de `système de fichiers`. Par exemple, le paramètre `d'url` pour `resolveLocalFileSystemURL` devrait être dans la forme `filesystem:file:///persistent/somefile.txt` par opposition à la forme `file:///persistent/somefile.txt` dans Android. -Déconseillée `toNativeURL` fonction n'est pas prise en charge et n'est pas une ébauche. -fonction de `setMetadata` n'est pas stipulée dans le devis et pas pris en charge. -INVALID_MODIFICATION_ERR (code: 9) est levée au lieu de SYNTAX_ERR(code: 8) sur la demande d'un système de fichier inexistant. -INVALID_MODIFICATION_ERR (code: 9) est levée au lieu de PATH_EXISTS_ERR(code: 12) à essayer de créer exclusivement un fichier ou un répertoire, qui existe déjà. -INVALID_MODIFICATION_ERR (code: 9) est levée au lieu de NO_MODIFICATION_ALLOWED_ERR(code: 6) à essayer d'appeler removeRecursively sur le système de fichiers racine. -INVALID_MODIFICATION_ERR (code: 9) est levée au lieu de NOT_FOUND_ERR(code: 1) en essayant de moveTo répertoire qui n'existe pas. + +### Base IndexedDB impl bizarreries (Firefox et IE) + + * `.` et `.` ne sont pas pris en charge. + * IE ne prend pas en charge les `file:///`-mode ; seul le mode hébergé est pris en charge (http://localhost:xxxx). + * Taille de système de fichiers de Firefox n'est pas limité, mais chaque extension de 50Mo demandera une autorisation de l'utilisateur. IE10 permet jusqu'à 10 Mo de combiné AppCache et IndexedDB utilisés dans la mise en œuvre du système de fichiers sans demander de confirmation, une fois que vous atteignez ce niveau, Qu'on vous demandera si vous souhaitez lui permettre d'être augmentée jusqu'à un maximum de 250 Mo par site. Si le paramètre de `taille` pour la fonction `requestFileSystem` n'affecte pas le système de fichiers dans Firefox et IE. + * fonction de `readAsBinaryString` n'est pas indiquée dans les spécifications et pas pris en charge dans Internet Explorer et n'a pas une ébauche. + * `file.type` est toujours null. + * Vous ne devez pas créer en utilisant le résultat du callback instance DirectoryEntry qui avait été supprimée. Sinon, vous obtiendrez une « entrée de pendaison ». + * Avant que vous pouvez lire un fichier qui a été écrit juste que vous devez obtenir une nouvelle instance de ce fichier. + * `setMetadata` fonction, qui n'est pas indiquée dans les spécifications supporte `modificationTime` changement de champ seulement. + * fonctions `copyTo` et `moveTo` ne supportent pas les répertoires. + * Répertoires métadonnées ne sont pas pris en charge. + * Les deux Entry.remove et directoryEntry.removeRecursively ne manquent pas lors de la suppression des répertoires non-vides - répertoires retirés sont nettoyés avec contenu au lieu de cela. + * fonctions `abort` et `truncate` ne sont pas supportées. + * événements de progression ne sont pas déclenchés. Par exemple, ce gestionnaire ne sera pas exécuté : + +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## Notes de mise à niveau + +V1.0.0 de ce plugin, les structures `FileEntry` et `DirectoryEntry` ont changé, pour être plus conforme à la spécification publiée. + +Les versions précédentes de (pré-1.0.0) du plugin stockaient le dispositif-absolu--emplacement du fichier dans la propriété `fullPath` d'objets `d'entrée`. Ces chemins seraient présente généralement comme + + / var/mobile/Applications/< application UUID >/Documents/chemin/vers/fichier (iOS), /storage/emulated/0/path/to/file (Android) + + +Ces chemins ont été également retournés par la méthode de `toURL()` les objets `d'entrée`. + +Avec v1.0.0, l'attribut `fullPath` est le chemin d'accès au fichier, *par rapport à la racine du système de fichiers HTML*. Ainsi, les chemins d'accès ci-dessus seraient maintenant tous les deux être représentée par un objet `FileEntry` avec un `fullPath` de + + /path/to/file + + +Si votre application fonctionne avec le dispositif-absolu-chemins et que vous avez récupéré précédemment ces chemins d'accès par le biais de la propriété `fullPath` d'objets `d'entrée`, puis vous devez mettre à jour votre code afin d'utiliser `entry.toURL()` à la place. + +Pour vers l'arrière la compatibilité, la méthode `resolveLocalFileSystemURL()` sera un chemin absolu de l'unité et retourne un objet `Entry` correspondant à elle, tant que ce fichier existe au sein des systèmes de fichiers les `TEMPORARY` ou `PERSISTENT`. + +Cela a été particulièrement un problème avec le plugin de transfert de fichiers, qui autrefois périphérique-absolu-chemins (et peut encore accepter). Il a été mis à jour pour fonctionner correctement avec le système de fichiers URL, afin de remplacer `entry.fullPath` par `entry.toURL()` devrait résoudre tout problème obtenir ce plugin pour travailler avec des fichiers sur le périphérique. + +Dans v1.1.0 la valeur de retour de `toURL()` a été changée (voir \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) pour renvoyer une URL absolue "file://". dans la mesure du possible. Pour assurer un ' cdvfile:'-URL, vous pouvez utiliser `toInternalURL()` maintenant. Cette méthode retourne maintenant filesystem URL du formulaire + + cdvfile://localhost/persistent/path/to/file + + +qui peut servir à identifier de manière unique le fichier. + +## Liste des Codes d'erreur et leur signification + +Lorsqu'une erreur est levée, l'un des codes suivants sera utilisé. + +| Code | Constant | +| ----:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Configuration du Plugin (facultatif) + +L'ensemble des systèmes de fichiers disponibles peut être configurée par plate-forme. Les iOS et Android reconnaissent une balise dans le `fichier config.xml` qui nomme les systèmes de fichiers à installer. Par défaut, toutes les racines du système de fichiers sont activées. + + + + + +### Android + + * `files` : répertoire de stockage de fichier interne de l'application + * `files-external` : répertoire de l'application de stockage de fichier externe + * `sdcard` : le répertoire de stockage global fichier externe (c'est la racine de la carte SD, s'il est installé). Vous devez avoir la permission de `android.permission.WRITE_EXTERNAL_STORAGE` de l'utiliser. + * `cache` : répertoire de cache interne de l'application + * `cache-external` : répertoire de cache externe de l'application + * `root` : le système de fichiers de tout dispositif + +Android prend également en charge un système de fichiers spécial nommé « documents », qui représente un sous-répertoire « / Documents / » dans le système de fichiers « files ». + +### iOS + + * `library` : répertoire de bibliothèque de l'application + * `documents` : répertoire de Documents de l'application + * `cache` : répertoire de Cache de l'application + * `bundle` : bundle de l'application ; l'emplacement de l'application elle-même sur disque (lecture seule) + * `root` : le système de fichiers de tout dispositif + +Par défaut, vous peuvent synchroniser les répertoires de la bibliothèque et les documents à iCloud. Vous pouvez également demander des deux systèmes de fichiers supplémentaires, `library-nosync` et `documents-nosync`, qui représentent un répertoire spécial non synchronisées dans le `/Library` ou système de fichiers `/ Documents`. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/fr/index.md b/mobile/plugins/cordova-plugin-file/doc/fr/index.md new file mode 100644 index 0000000..7235522 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/fr/index.md @@ -0,0 +1,331 @@ + + +# cordova-plugin-file + +Ce plugin implémente une API de fichier permettant l'accès en lecture/écriture aux fichiers qui résident sur le périphérique. + +Ce plugin est basé sur plusieurs spécifications, y compris : l'API de fichier HTML5 + +Les répertoires (aujourd'hui disparue) et le système des extensions plus récentes : bien que la plupart du code du plugin a été écrit quand une technique antérieure était en vigueur : + +Il met également en œuvre la spécification FileWriter : + +Pour son utilisation, veuillez vous reporter au HTML5 Rocks' excellent [article de système de fichiers.][1] + + [1]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +Pour un aperçu des autres options de stockage, consultez [guide d'entreposage de Cordova][2]. + + [2]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +Ce plugin définit global `cordova.file` objet. + +Bien que dans la portée globale, il n'est pas disponible jusqu'après la `deviceready` événement. + + document.addEventListener (« deviceready », onDeviceReady, false) ; + function onDeviceReady() {console.log(cordova.file);} + + +## Installation + + Cordova plugin ajouter cordova-plugin-file + + +## Plates-formes prises en charge + +* Amazon Fire OS +* Android +* BlackBerry 10 +* Firefox OS +* iOS +* Windows Phone 7 et 8 * +* Windows 8 * +* Navigateur + +* *Ces plates-formes ne supportent pas `FileReader.readAsArrayBuffer` ni `FileWriter.write(blob)` .* + +## Emplacement de stockage des fichiers + +À partir de v1.2.0, URL vers des répertoires de système de fichiers importants est fournis. Chaque URL est dans la forme *file:///path/to/spot/*et peut être converti en un `DirectoryEntry` à l'aide`window.resolveLocalFileSystemURL()`. + +* `cordova.file.applicationDirectory`-Lecture seule répertoire où l'application est installée. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.applicationStorageDirectory`-Répertoire racine du bac à sable de l'application ; cet endroit est en lecture seule sur iOS (mais les sous-répertoires spécifiques [comme `/Documents` ] sont en lecture / écriture). Toutes les données qu'il contient est privé de l'application. ( *iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.dataDirectory`-Stockage des données persistants et privés au sein de bac à sable de l'application à l'aide de la mémoire interne (sur Android, si vous avez besoin d'utiliser une mémoire externe, utilisez `.externalDataDirectory` ). Sur iOS, ce répertoire n'est pas synchronisé avec iCloud (utiliser `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.cacheDirectory`-Répertoire pour les fichiers de données en mémoire cache ou les fichiers que votre application peut recréer facilement. L'OS peut supprimer ces fichiers lorsque l'appareil faiblit sur stockage, néanmoins, les applications ne doivent pas compter sur l'OS pour supprimer les fichiers ici. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.externalApplicationStorageDirectory`-Espace l'application sur le stockage externe. (*Android*) + +* `cordova.file.externalDataDirectory`-Où placer les fichiers de données d'application spécifiques sur le stockage externe. (*Android*) + +* `cordova.file.externalCacheDirectory`-Cache de l'application sur le stockage externe. (*Android*) + +* `cordova.file.externalRootDirectory`-Racine de stockage externe (carte SD). (*Android*, *BlackBerry 10*) + +* `cordova.file.tempDirectory`-Répertoire temp que l'OS peut effacer à volonté. Ne comptez pas sur l'OS pour effacer ce répertoire ; votre application doit toujours supprimer les fichiers selon le cas. (*iOS*) + +* `cordova.file.syncedDataDirectory`-Contient des fichiers d'app spécifique qui doivent se synchroniser (par exemple à iCloud). (*iOS*) + +* `cordova.file.documentsDirectory`-Fichiers privés à l'app, mais qui sont significatives pour l'autre application (par exemple les fichiers Office). (*iOS*) + +* `cordova.file.sharedDirectory`-Fichiers disponibles globalement à toutes les applications (*BlackBerry 10*) + +## Structures de système de fichiers + +Bien que techniquement un détail d'implémentation, il peut être très utile de savoir comment les `cordova.file.*` carte de propriétés à des chemins d'accès physiques sur un périphérique réel. + +### iOS agencement de système de fichier + +| Chemin de l'unité | `Cordova.file.*` | `iosExtraFileSystems` | r/w ? | persistants ? | OS efface | Sync | privé | +|:-------------------------------------------- |:--------------------------- |:--------------------- |:-----:|:-------------:|:-----------:|:-----:|:-----:| +| `/ var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N/A | N/A | N/A | Oui | +|    `appname.app/` | applicationDirectory | Bundle | r | N/A | N/A | N/A | Oui | +|       `www/` | - | - | r | N/A | N/A | N/A | Oui | +|    `Documents/` | documentsDirectory | documents | r/w | Oui | Non | Oui | Oui | +|       `NoCloud/` | - | documents-nosync | r/w | Oui | Non | Non | Oui | +|    `Library` | - | Bibliothèque | r/w | Oui | Non | Oui ? | Oui | +|       `NoCloud/` | dataDirectory | Bibliothèque-nosync | r/w | Oui | Non | Non | Oui | +|       `Cloud/` | syncedDataDirectory | - | r/w | Oui | Non | Oui | Oui | +|       `Caches/` | cacheDirectory | cache | r/w | Oui * | Oui * * *| | Non | Oui | +|    `tmp/` | tempDirectory | - | r/w | Ne * * | Oui * * *| | Non | Oui | + +* Fichiers persistent à travers les redémarrages de l'application et mises à niveau, mais ce répertoire peut être effacé à chaque fois que les désirs de l'OS. Votre application doit être en mesure de recréer tout contenu qui pourrait être supprimé. + +* * Fichiers peuvent persister redémarrages de l'application, mais ne vous fiez pas ce comportement. Les fichiers ne sont pas garantis à persister dans l'ensemble de mises à jour. Votre application doit supprimer les fichiers de ce répertoire lorsqu'elle s'applique, comme le système d'exploitation ne garantit pas quand (ou même si) ces fichiers sont supprimés. + +* * *| L'OS peut effacer le contenu de ce répertoire chaque fois qu'il se sent il est nécessaire, mais ne comptez pas là-dessus. Vous devez supprimer ce répertoire comme approprié pour votre application. + +### Agencement de système de fichiers Android + +| Chemin de l'unité | `Cordova.file.*` | `AndroidExtraFileSystems` | r/w ? | persistants ? | OS efface | privé | +|:----------------------------------- |:----------------------------------- |:------------------------- |:-----:|:-------------:|:---------:|:-----:| +| `file:///android_asset/` | applicationDirectory | | r | N/A | N/A | Oui | +| `/ données/data/app < id > /` | applicationStorageDirectory | - | r/w | N/A | N/A | Oui | +|    `cache` | cacheDirectory | cache | r/w | Oui | Oui * | Oui | +|    `files` | dataDirectory | fichiers | r/w | Oui | Non | Oui | +|       `Documents` | | documents | r/w | Oui | Non | Oui | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | Oui | Non | Non | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Oui | Non | Non | +|       `cache` | externalCacheDirectry | cache-externe | r/w | Oui | Ne * * | Non | +|       `files` | externalDataDirectory | fichiers externes | r/w | Oui | Non | Non | + +* Le système d'exploitation peut effacer périodiquement ce répertoire, mais ne vous fiez pas ce comportement. Effacer le contenu de ce répertoire comme approprié pour votre application. Un utilisateur doit purger le cache manuellement, le contenu de ce répertoire est supprimé. + +* * The OS vous n'effacez pas ce répertoire automatiquement ; vous êtes chargé de gérer le contenu vous-même. L'utilisateur devrait purger le cache manuellement, le contenu du répertoire est supprimé. + +**Remarque**: si le stockage externe ne peut pas être monté, les `cordova.file.external*` sont des propriétés`null`. + +### Configuration du système blackBerry 10 fichier + +| Chemin de l'unité | `Cordova.file.*` | r/w ? | persistants ? | OS efface | privé | +|:--------------------------------------------------- |:--------------------------- |:-----:|:-------------:|:---------:|:-----:| +| `file:///Accounts/1000/AppData/ < id app > /` | applicationStorageDirectory | r | N/A | N/A | Oui | +|    `app/native` | applicationDirectory | r | N/A | N/A | Oui | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | Non | Oui | Oui | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Oui | Non | Oui | +| `file:///Accounts/1000/Removable/sdcard` | externalRemovableDirectory | r/w | Oui | Non | Non | +| `file:///Accounts/1000/Shared` | sharedDirectory | r/w | Oui | Non | Non | + +*Remarque*: lorsque l'application est déployée dans le périmètre de travail, tous les chemins sont par rapport à /accounts/1000-enterprise. + +## Quirks Android + +### Emplacement de stockage persistant Android + +Il y a plusieurs emplacements valides pour stocker des fichiers persistants sur un appareil Android. Voir [cette page][3] pour une analyse approfondie des diverses possibilités. + + [3]: http://developer.android.com/guide/topics/data/data-storage.html + +Les versions précédentes du plugin choisirait l'emplacement des fichiers temporaires et persistantes au démarrage, basé sur la question de savoir si le dispositif réclamé que la carte SD (ou une partition de stockage équivalent) a été montée. Si la carte SD a été montée, ou si une partition de stockage interne importante était disponible (comme sur les appareils Nexus,) puis les fichiers persistants seraient stockés dans la racine de cet espace. Cela signifie que toutes les apps de Cordova pouvaient voir tous les fichiers disponibles sur la carte. + +Si la carte SD n'était pas disponible, les versions précédentes pourraient stocker des données sous `/data/data/` , qui isole des apps de l'autre, mais peut encore cause données à partager entre les utilisateurs. + +Il est maintenant possible de choisir de stocker les fichiers dans l'emplacement de stockage de fichier interne, ou en utilisant la logique précédente, avec une préférence au sein de votre application `config.xml` fichier. Pour ce faire, ajoutez l'un de ces deux lignes de `config.xml` : + + < nom de l'option = « AndroidPersistentFileLocation » value = « Internal » / >< nom de préférence = « AndroidPersistentFileLocation » value = « Compatibilité » / > + + +Sans cette ligne, utilisera le fichier plugin `Compatibility` par défaut. Si une balise de préférence est présente et n'est pas une des valeurs suivantes, l'application ne démarrera pas. + +Si votre application a déjà été expédiée aux utilisateurs, en utilisant une ancienne (avant 1.0) version de ce plugin et dispose des fichiers stockés dans le système de fichiers persistant, alors vous devez définir la préférence au `Compatibility` . Commutation de l'emplacement « Internal » signifierait que les utilisateurs existants qui mettre à niveau leur application peuvent être impossible d'accéder à leurs fichiers déjà enregistrés, selon leur appareil. + +Si votre application est nouvelle ou a jamais précédemment stocké les fichiers dans le système de fichiers persistant, puis la `Internal` réglage est généralement recommandé. + +## iOS Quirks + +* `cordova.file.applicationStorageDirectory`est en lecture seule ; tentative de stocker des fichiers dans le répertoire racine échoue. Utilisez l'une de l'autre `cordova.file.*` les propriétés définies pour iOS (seulement `applicationDirectory` et `applicationStorageDirectory` sont en lecture seule). +* `FileReader.readAsText(blob, encoding)` + * Le `encoding` paramètre n'est pas pris en charge, et le codage UTF-8 est toujours en vigueur. + +### emplacement de stockage persistant d'iOS + +Il y a deux emplacements valides pour stocker des fichiers persistants sur un appareil iOS : le répertoire de Documents et le répertoire de la bibliothèque. Les versions précédentes du plugin stockaient ne jamais fichiers persistants dans le répertoire de Documents. Cela a eu l'effet secondaire de rendre tous les fichiers de l'application visible dans iTunes, qui était souvent inattendus, en particulier pour les applications qui traitent beaucoup de petits fichiers, plutôt que de produire des documents complets destinés à l'exportation, qui est l'objectif visé par le répertoire. + +Il est maintenant possible de choisir de stocker les fichiers dans le répertoire de bibliothèque, avec une préférence au sein de votre application ou de documents `config.xml` fichier. Pour ce faire, ajoutez l'un de ces deux lignes de `config.xml` : + + < nom de l'option = « iosPersistentFileLocation » value = « Library » / >< nom de préférence = « iosPersistentFileLocation » value = « Compatibilité » / > + + +Sans cette ligne, utilisera le fichier plugin `Compatibility` par défaut. Si une balise de préférence est présente et n'est pas une des valeurs suivantes, l'application ne démarrera pas. + +Si votre application a déjà été expédiée aux utilisateurs, en utilisant une ancienne (avant 1.0) version de ce plugin et dispose des fichiers stockés dans le système de fichiers persistant, alors vous devez définir la préférence au `Compatibility` . Changer l'emplacement de `Library` voudrait dire que les utilisateurs existants qui mettre à niveau leur application serait incapables d'accéder à leurs fichiers déjà enregistrés. + +Si votre application est nouvelle ou a jamais précédemment stocké les fichiers dans le système de fichiers persistant, puis la `Library` réglage est généralement recommandé. + +## Firefox OS Quirks + +L'API de système de fichier n'est pas nativement pris en charge par Firefox OS et est implémentée comme une cale d'épaisseur sur le dessus d'indexedDB. + +* Ne manque pas lors de la suppression des répertoires non vide +* Ne supporte pas les métadonnées pour les répertoires +* Méthodes `copyTo` et `moveTo` ne prennent pas en charge les répertoires + +Les chemins de données suivants sont pris en charge: * `applicationDirectory` -utilise `xhr` pour obtenir des fichiers les qui sont emballées avec l'app. * `dataDirectory` - Pour les fichiers de données persistantes de app spécifique. * `cacheDirectory` -Mise en cache de fichiers qui doivent survivre les redémarrages de l'application (les applications ne doivent pas compter sur le système d'exploitation pour supprimer les fichiers ici). + +## Bizarreries navigateur + +### Commune de bizarreries et de remarques + +* Chaque navigateur utilise son propre système de fichiers en bac à sable. IE et Firefox utilisent IndexedDB comme base. Tous les navigateurs utilisent oblique comme séparateur de répertoire dans un chemin d'accès. +* Entrées d'annuaire doivent être créées successivement. Par exemple, l'appel `fs.root.getDirectory (' dir1/dir2 ', {create:true}, successCallback, errorCallback)` échouera si dir1 n'existait pas. +* Le plugin demande utilisateur l'autorisation d'utiliser le stockage persistant lors du premier démarrage d'application. +* Plugin supporte `cdvfile://localhost` (ressources locales) seulement. C'est-à-dire les ressources externes ne sont pas supportés par l'intermédiaire de `cdvfile`. +* Le plugin ne suit pas les ["Restrictions de nommage des fichiers système API 8.3"][4]. +* BLOB et le fichier "`close` la fonction n'est pas pris en charge. +* `FileSaver` et `BlobBuilder` ne sont pas pris en charge par ce plugin et n'ont stubs. +* Le plugin ne supporte pas les `requestAllFileSystems`. Cette fonction est également absent dans les cahier des charges. +* Inscriptions dans l'annuaire ne seront pas supprimées si vous utilisez `create: true` drapeau pour le répertoire existant. +* Fichiers créés via le constructeur ne sont pas pris en charge. Vous devez plutôt utiliser entry.file méthode. +* Chaque navigateur utilise sa propre forme de références URL blob. +* `readAsDataURL` fonction est prise en charge, mais le mediatype en Chrome dépend de l'extension entrée, mediatype dans IE est toujours vide (qui est le même que le `texte-plaine` selon la spécification), le mediatype dans Firefox est toujours `application/octet-stream`. Par exemple, si le contenu est `abcdefg` puis Firefox renvoie `données : application / octet-stream ; base64, YWJjZGVmZw ==`, c'est à dire les retours `données:; base64, YWJjZGVmZw ==`, retours de Chrome `données : < mediatype selon l'extension de nom d'entrée > ; base64, YWJjZGVmZw ==`. +* `toInternalURL` retourne le chemin d'accès dans le formulaire `file:///persistent/path/to/entry` (Firefox, IE). Chrome retourne le chemin d'accès dans le formulaire `cdvfile://localhost/persistent/file`. + + [4]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions + +### Bizarreries de chrome + +* Chrome filesystem n'est pas prête immédiatement après l'événement ready périphérique. Pour contourner le problème, vous pouvez vous abonner à l'événement `filePluginIsReady`. Exemple : + + javascript + window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); + + +Vous pouvez utiliser la fonction `window.isFilePluginReadyRaised` pour vérifier si les événement était déjà déclenché. -quotas de window.requestFileSystem temporaire et permanent de système de fichiers ne sont pas limités en Chrome. -Pour augmenter le stockage persistant en Chrome, vous devez appeler la méthode `window.initPersistentFileSystem`. Quota de stockage persistant est 5 Mo par défaut. -Chrome nécessite `--permettre-fichier-accès-de-fichiers` exécuter l'argument au support API via le protocole `file:///`. -`Fichier` objet changera pas si vous utilisez le drapeau `{create:true}` lors du passage d'une `entrée` existante. -événements `annulables` propriété a la valeur true dans Chrome. Il s'agit à l'encontre de la [spécification][5]. -`toURL` renvoie à Chrome `système de fichiers :`-préfixe de chemin d'accès selon l'application hôte. Par exemple, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -résultat de la fonction `toURL` ne contient-elle pas de barre oblique dans le cas d'entrée d'annuaire. Chrome résout répertoires avec barre oblique-trainés URL correctement cependant. -`resolveLocalFileSystemURL` méthode nécessite l' entrant `url` préfixe de `système de fichiers`. Par exemple, le paramètre `d'url` pour `resolveLocalFileSystemURL` devrait être dans la forme `filesystem:file:///persistent/somefile.txt` par opposition à la forme `file:///persistent/somefile.txt` dans Android. -Déconseillée `toNativeURL` fonction n'est pas prise en charge et n'est pas une ébauche. -fonction de `setMetadata` n'est pas stipulée dans le devis et pas pris en charge. -INVALID_MODIFICATION_ERR (code: 9) est levée au lieu de SYNTAX_ERR(code: 8) sur la demande d'un système de fichier inexistant. -INVALID_MODIFICATION_ERR (code: 9) est levée au lieu de PATH_EXISTS_ERR(code: 12) à essayer de créer exclusivement un fichier ou un répertoire, qui existe déjà. -INVALID_MODIFICATION_ERR (code: 9) est levée au lieu de NO_MODIFICATION_ALLOWED_ERR(code: 6) à essayer d'appeler removeRecursively sur le système de fichiers racine. -INVALID_MODIFICATION_ERR (code: 9) est levée au lieu de NOT_FOUND_ERR(code: 1) en essayant de moveTo répertoire qui n'existe pas. + + [5]: http://dev.w3.org/2009/dap/file-system/file-writer.html + +### Base IndexedDB impl bizarreries (Firefox et IE) + +* `.` et `.` ne sont pas pris en charge. +* IE ne prend pas en charge les `file:///`-mode ; seul le mode hébergé est pris en charge (http://localhost:xxxx). +* Taille de système de fichiers de Firefox n'est pas limité, mais chaque extension de 50Mo demandera une autorisation de l'utilisateur. IE10 permet jusqu'à 10 Mo de combiné AppCache et IndexedDB utilisés dans la mise en œuvre du système de fichiers sans demander de confirmation, une fois que vous atteignez ce niveau, Qu'on vous demandera si vous souhaitez lui permettre d'être augmentée jusqu'à un maximum de 250 Mo par site. Si le paramètre de `taille` pour la fonction `requestFileSystem` n'affecte pas le système de fichiers dans Firefox et IE. +* fonction de `readAsBinaryString` n'est pas indiquée dans les spécifications et pas pris en charge dans Internet Explorer et n'a pas une ébauche. +* `file.type` est toujours null. +* Vous ne devez pas créer en utilisant le résultat du callback instance DirectoryEntry qui avait été supprimée. Sinon, vous obtiendrez une « entrée de pendaison ». +* Avant que vous pouvez lire un fichier qui a été écrit juste que vous devez obtenir une nouvelle instance de ce fichier. +* `setMetadata` fonction, qui n'est pas indiquée dans les spécifications supporte `modificationTime` changement de champ seulement. +* fonctions `copyTo` et `moveTo` ne supportent pas les répertoires. +* Répertoires métadonnées ne sont pas pris en charge. +* Les deux Entry.remove et directoryEntry.removeRecursively ne manquent pas lors de la suppression des répertoires non-vides - répertoires retirés sont nettoyés avec contenu au lieu de cela. +* fonctions `abort` et `truncate` ne sont pas supportées. +* événements de progression ne sont pas déclenchés. Par exemple, ce gestionnaire ne sera pas exécuté : + + javascript + writer.onprogress = function() { /*commands*/ }; + + +## Notes de mise à niveau + +V1.0.0 de ce plugin, les structures `FileEntry` et `DirectoryEntry` ont changé, pour être plus conforme à la spécification publiée. + +Les versions précédentes de (pré-1.0.0) du plugin stockaient le dispositif-absolu--emplacement du fichier dans la propriété `fullPath` d'objets `d'entrée`. Ces chemins seraient présente généralement comme + + / var/mobile/Applications/< application UUID >/Documents/chemin/vers/fichier (iOS), /storage/emulated/0/path/to/file (Android) + + +Ces chemins ont été également retournés par la méthode de `toURL()` les objets `d'entrée`. + +Avec v1.0.0, l'attribut `fullPath` est le chemin d'accès au fichier, *par rapport à la racine du système de fichiers HTML*. Ainsi, les chemins d'accès ci-dessus seraient maintenant tous les deux être représentée par un objet `FileEntry` avec un `fullPath` de + + /path/to/file + + +Si votre application fonctionne avec le dispositif-absolu-chemins et que vous avez récupéré précédemment ces chemins d'accès par le biais de la propriété `fullPath` d'objets `d'entrée`, puis vous devez mettre à jour votre code afin d'utiliser `entry.toURL()` à la place. + +Pour vers l'arrière la compatibilité, la méthode `resolveLocalFileSystemURL()` sera un chemin absolu de l'unité et retourne un objet `Entry` correspondant à elle, tant que ce fichier existe au sein des systèmes de fichiers les `TEMPORARY` ou `PERSISTENT`. + +Cela a été particulièrement un problème avec le plugin de transfert de fichiers, qui autrefois périphérique-absolu-chemins (et peut encore accepter). Il a été mis à jour pour fonctionner correctement avec le système de fichiers URL, afin de remplacer `entry.fullPath` par `entry.toURL()` devrait résoudre tout problème obtenir ce plugin pour travailler avec des fichiers sur le périphérique. + +Dans v1.1.0 la valeur de retour de `toURL()` a été changée (voir \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) pour renvoyer une URL absolue "file://". dans la mesure du possible. Pour assurer un ' cdvfile:'-URL, vous pouvez utiliser `toInternalURL()` maintenant. Cette méthode retourne maintenant filesystem URL du formulaire + + cdvfile://localhost/persistent/path/to/file + + +qui peut servir à identifier de manière unique le fichier. + +## Liste des Codes d'erreur et leur signification + +Lorsqu'une erreur est levée, l'un des codes suivants sera utilisé. + +| Code | Constant | +| ----:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Configuration du Plugin (facultatif) + +L'ensemble des systèmes de fichiers disponibles peut être configurée par plate-forme. Les iOS et Android reconnaissent une balise dans le `fichier config.xml` qui nomme les systèmes de fichiers à installer. Par défaut, toutes les racines du système de fichiers sont activées. + + + + + +### Android + +* `files` : répertoire de stockage de fichier interne de l'application +* `files-external` : répertoire de l'application de stockage de fichier externe +* `sdcard` : le répertoire de stockage global fichier externe (c'est la racine de la carte SD, s'il est installé). Vous devez avoir la permission de `android.permission.WRITE_EXTERNAL_STORAGE` de l'utiliser. +* `cache` : répertoire de cache interne de l'application +* `cache-external` : répertoire de cache externe de l'application +* `root` : le système de fichiers de tout dispositif + +Android prend également en charge un système de fichiers spécial nommé « documents », qui représente un sous-répertoire « / Documents / » dans le système de fichiers « files ». + +### iOS + +* `library` : répertoire de bibliothèque de l'application +* `documents` : répertoire de Documents de l'application +* `cache` : répertoire de Cache de l'application +* `bundle` : bundle de l'application ; l'emplacement de l'application elle-même sur disque (lecture seule) +* `root` : le système de fichiers de tout dispositif + +Par défaut, vous peuvent synchroniser les répertoires de la bibliothèque et les documents à iCloud. Vous pouvez également demander des deux systèmes de fichiers supplémentaires, `library-nosync` et `documents-nosync`, qui représentent un répertoire spécial non synchronisées dans le `/Library` ou système de fichiers `/ Documents`. diff --git a/mobile/plugins/cordova-plugin-file/doc/fr/plugins.md b/mobile/plugins/cordova-plugin-file/doc/fr/plugins.md new file mode 100644 index 0000000..b04e17f --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/fr/plugins.md @@ -0,0 +1,101 @@ + + +# Notes pour les développeurs de plugins + +Ces notes sont principalement destinés à des développeurs Android et iOS qui veulent écrire des plugins qui interface avec le système de fichiers en utilisant le fichier plugin. + +## Travailler avec Cordova fichier système URL + +Depuis la version 1.0.0, ce plugin utilise des URL avec un `cdvfile` guichet pour toutes les communications sur le pont, plutôt que d'exposer des chemins de système de fichiers de périphérique brut à JavaScript. + +Du côté du JavaScript, cela signifie que les objets FileEntry et DirectoryEntry ont un attribut fullPath qui est relatif à la racine du système de fichiers HTML. Si votre plugin JavaScript API accepte un objet FileEntry ou DirectoryEntry, vous devez appeler `.toURL()` sur cet objet avant de le passer sur le pont en code natif. + +### Conversion de cdvfile: / / URL aux chemins d'accès fileystem + +Plugins qui ont besoin d'écrire dans le système de fichiers pouvez convertir un fichier reçu système URL vers un emplacement de système de fichiers réels. Il y a plusieurs façons de le faire, selon la plate-forme native. + +Il est important de rappeler que pas tous les `cdvfile://` URL sont cartographiables à des fichiers sur le périphérique. Certaines URL peut faire référence aux actifs sur les périphériques qui ne sont pas représentés par des fichiers, ou peuvent même faire référence aux ressources distantes. En raison de ces possibilités, plugins devraient toujours tester si ils obtiennent un résultat significatif retour lorsque vous essayez de convertir les URL aux chemins d'accès. + +#### Androïde + +Sur Android, la méthode la plus simple pour convertir un `cdvfile://` URL vers un chemin d'accès de système de fichiers est d'utiliser `org.apache.cordova.CordovaResourceApi` . `CordovaResourceApi`possède plusieurs méthodes qui peuvent gérer `cdvfile://` URL : + + webView est membre de la Plugin classe CordovaResourceApi resourceApi = webView.getResourceApi() ; + + Obtenir une URL file:/// représentant ce fichier sur le périphérique, / / ou le même URL inchangée si elle ne peut pas être mappée à un fichier Uri fileURL = resourceApi.remapUri(Uri.parse(cdvfileURL)) ; + + +Il est également possible d'utiliser le fichier plugin directement : + + Import org.apache.cordova.file.FileUtils ; + Import org.apache.cordova.file.FileSystem ; + java.net.MalformedURLException d'importation ; + + Téléchargez le fichier plugin depuis le gestionnaire de plugin FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File") ; + + En donnant une URL, obtenir un chemin d'accès pour essayer {String path = filePlugin.filesystemPathForURL(cdvfileURL);} catch (MalformedURLException e) {/ / l'url du système de fichiers n'a pas été reconnu} + + +Pour convertir un chemin d'accès à un `cdvfile://` URL : + + Import org.apache.cordova.file.LocalFilesystemURL ; + + Obtenir un objet LocalFilesystemURL pour un chemin de périphérique, / / ou null si elle ne peut être représentée sous forme d'URL cdvfile. + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path) ; + Obtenir la chaîne représentant l'URL objet String cdvfileURL = url.toString() ; + + +Si votre plugin crée un fichier et que vous souhaitez renvoyer un objet FileEntry pour cela, utilisez le fichier plugin : + + Retourne une structure JSON approprié pour revenir en JavaScript, / / ou null si ce fichier n'est pas représentable sous forme d'URL cdvfile. + JSONObject entrée = filePlugin.getEntryForFile(file) ; + + +#### iOS + +Cordova sur iOS n'utilise pas le même `CordovaResourceApi` concept d'Android. Sur iOS, vous devez utiliser le fichier plugin pour convertir entre les URL et les chemins d'accès de système de fichiers. + + Obtenir un objet URL CDVFilesystem partir d'une chaîne d'URL CDVFilesystemURL * url = [CDVFilesystemURL fileSystemURLWithString:cdvfileURL] ; + Obtenir un chemin d'accès de l'objet URL, ou zéro si elle ne peut pas être mappée à un chemin de fichier NSString * = [filePlugin filesystemPathForURL:url] ; + + + Obtenir un objet CDVFilesystem URL pour un chemin de périphérique, ou / / zéro si elle ne peut être représentée sous forme d'URL cdvfile. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path] ; + Obtenir la représentation de chaîne de l'objet NSString * cdvfileURL URL = [url absoluteString] ; + + +Si votre plugin crée un fichier et que vous souhaitez renvoyer un objet FileEntry pour cela, utilisez le fichier plugin : + + Obtenir un objet CDVFilesystem URL pour un chemin de périphérique, ou / / zéro si elle ne peut être représentée sous forme d'URL cdvfile. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path] ; + Obtenir une structure pour revenir à JavaScript NSDictionary * entrée = [filePlugin makeEntryForLocalURL:url] + + +#### JavaScript + +En JavaScript, pour obtenir un `cdvfile://` URL d'un objet FileEntry ou DirectoryEntry, il suffit d'appeler `.toURL()` à ce sujet : + + var cdvfileURL = entry.toURL() ; + + +Dans gestionnaires de plugin de réponse, pour convertir une structure FileEntry retournée vers un objet réel de l'entrée, votre code de gestionnaire doit importer le fichier plugin et créer un nouvel objet : + + créer l'entrée de var d'objet entrée appropriée ; + Si (entryStruct.isDirectory) {entrée = new DirectoryEntry (entryStruct.name, entryStruct.fullPath, nouveau FileSystem(entryStruct.filesystemName));} else {entrée = nouvelle FileEntry (entryStruct.name, entryStruct.fullPath, nouvelle FileSystem(entryStruct.filesystemName));} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/it/README.md b/mobile/plugins/cordova-plugin-file/doc/it/README.md new file mode 100644 index 0000000..f8e302f --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/it/README.md @@ -0,0 +1,335 @@ + + +# cordova-plugin-file + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg)](https://travis-ci.org/apache/cordova-plugin-file) + +Questo plugin implementa un API File permettendo l'accesso di lettura/scrittura ai file che risiedono sul dispositivo. + +Questo plugin si basa su diverse specifiche, tra cui: The HTML5 File API + +Le directory (ormai defunta) e il sistema delle estensioni più recenti: anche se la maggior parte del codice plugin è stato scritto quando una spec precedenti era corrente: + +Implementa inoltre FileWriter spec: + +Per l'utilizzo, fare riferimento a HTML5 Rocks' eccellente [articolo FileSystem.](http://www.html5rocks.com/en/tutorials/file/filesystem/) + +Per una panoramica delle altre opzioni di archiviazione, consultare [Guida di archiviazione di Cordova](http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html). + +Questo plugin definisce oggetto global `cordova.file`. + +Anche se in ambito globale, non è disponibile fino a dopo l'evento `deviceready`. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## Installazione + + cordova plugin add cordova-plugin-file + + +## Piattaforme supportate + + * Amazon fuoco OS + * Android + * BlackBerry 10 + * Firefox OS + * iOS + * Windows Phone 7 e 8 * + * Windows 8 * + * Windows* + * Browser + +\* *These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`.* + +## Dove memorizzare i file + +A partire dalla v 1.2.0, vengono forniti gli URL per le directory importanti file di sistema. Ogni URL è nella forma *file:///path/to/spot/* e può essere convertito in un `DirectoryEntry` utilizzando `window.resolveLocalFileSystemURL()`. + + * `cordova.file.applicationDirectory`-Sola lettura directory dove è installato l'applicazione. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.applicationStorageDirectory`-Directory radice di sandbox dell'applicazione; su iOS questa posizione è in sola lettura (ma sottodirectory specifiche [come `/Documents` ] sono di sola lettura). Tutti i dati contenuti all'interno è privato all'app. ( *iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.dataDirectory`-Archiviazione dati persistente e privati nella sandbox dell'applicazione utilizzando la memoria interna (su Android, se è necessario utilizzare la memoria esterna, utilizzare `.externalDataDirectory` ). IOS, questa directory non è sincronizzata con iCloud (utilizzare `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.cacheDirectory`-Directory per i file memorizzati nella cache di dati o qualsiasi file che app possibile ricreare facilmente. L'OS può eliminare questi file quando il dispositivo viene eseguito basso sull'archiviazione, tuttavia, apps non deve basarsi sul sistema operativo per cancellare i file qui. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.externalApplicationStorageDirectory`-Spazio applicazione su storage esterno. (*Android*) + + * `cordova.file.externalDataDirectory`-Dove mettere i file di dati specifico app su storage esterno. (*Android*) + + * `cordova.file.externalCacheDirectory`-Cache applicazione su storage esterno. (*Android*) + + * `cordova.file.externalRootDirectory`-Radice di archiviazione esterna (scheda SD). (*Android*, *BlackBerry, 10*) + + * `cordova.file.tempDirectory`-Temp directory che l'OS è possibile cancellare a volontà. Non fare affidamento sul sistema operativo per cancellare questa directory; l'app deve sempre rimuovere file come applicabile. (*iOS*) + + * `cordova.file.syncedDataDirectory`-Contiene i file app specifiche che devono essere sincronizzati (per esempio a iCloud). (*iOS*) + + * `cordova.file.documentsDirectory`-I file privati per le app, ma che sono significativi per altre applicazioni (ad esempio i file di Office). (*iOS*) + + * `cordova.file.sharedDirectory`-File disponibili globalmente a tutte le applicazioni (*BlackBerry 10*) + +## Layout dei file di sistema + +Anche se tecnicamente un dettaglio di implementazione, può essere molto utile per conoscere come le proprietà `cordova.file.*` mappa di percorsi fisici su un dispositivo reale. + +### iOS File sistema Layout + +| Percorso dispositivo | `Cordova.file.*` | `iosExtraFileSystems` | r/w? | persistente? | OS cancella | sincronizzazione | privato | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:----:|:------------:|:------------:|:----------------:|:-------:| +| `/ var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N/A | N/A | N/A | Sì | +|    `appname.app/` | applicationDirectory | bundle | r | N/A | N/A | N/A | Sì | +|       `www/` | - | - | r | N/A | N/A | N/A | Sì | +|    `Documents/` | documentsDirectory | documenti | r/w | Sì | No | Sì | Sì | +|       `NoCloud/` | - | nosync-documenti | r/w | Sì | No | No | Sì | +|    `Library` | - | libreria | r/w | Sì | No | Sì? | Sì | +|       `NoCloud/` | dataDirectory | nosync-libreria | r/w | Sì | No | No | Sì | +|       `Cloud/` | syncedDataDirectory | - | r/w | Sì | No | Sì | Sì | +|       `Caches/` | cacheDirectory | cache | r/w | Sì * | Sì**\* | No | Sì | +|    `tmp/` | tempDirectory | - | r/w | No** | Sì**\* | No | Sì | + +\ * File persistono tra riavvii app e aggiornamenti, ma questa directory può essere cancellata ogni volta che il sistema operativo desideri. L'app dovrebbe essere in grado di ricreare qualsiasi contenuto che potrebbe essere eliminato. + +** File possono persistere riavvii del app, ma non fare affidamento su questo comportamento. I file non sono garantiti a persistere attraverso gli aggiornamenti. L'app deve rimuovere i file dalla directory quando è applicabile, come il sistema operativo non garantisce quando (o anche se) questi file vengono rimossi. + +**\ * The OS può cancellare il contenuto di questa directory ogni volta che si sente è necessario, ma non fare affidamento su questo. Si dovrebbe cancellare questa directory come adatto per l'applicazione. + +### Layout sistema Android File + +| Percorso dispositivo | `Cordova.file.*` | `AndroidExtraFileSystems` | r/w? | persistente? | OS cancella | privato | +|:------------------------------------------------ |:----------------------------------- |:------------------------- |:----:|:------------:|:-----------:|:-------:| +| `File:///android_asset/` | applicationDirectory | | r | N/A | N/A | Sì | +| `< app-id > /dati/dati / /` | applicationStorageDirectory | - | r/w | N/A | N/A | Sì | +|    `cache` | cacheDirectory | cache | r/w | Sì | Sì\* | Sì | +|    `files` | dataDirectory | file | r/w | Sì | No | Sì | +|       `Documents` | | documenti | r/w | Sì | No | Sì | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | Sì | No | No | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Sì | No | No | +|       `cache` | externalCacheDirectry | cache-esterno | r/w | Sì | No** | No | +|       `files` | externalDataDirectory | file-esterno | r/w | Sì | No | No | + +\ * Il sistema operativo può cancellare periodicamente questa directory, ma non fare affidamento su questo comportamento. Cancellare il contenuto di questa directory come adatto per l'applicazione. Il contenuto di questa directory dovrebbe un utente eliminare manualmente la cache, vengono rimossi. + +** Il sistema operativo non cancella questa directory automaticamente; Siete responsabili di gestire i contenuti da soli. Il contenuto della directory dovrebbe l'utente eliminare manualmente la cache, vengono rimossi. + +**Nota**: se la memorizzazione esterna non può essere montato, le proprietà `cordova.file.external*` sono `null`. + +### BlackBerry 10 File sistema Layout + +| Percorso dispositivo | `Cordova.file.*` | r/w? | persistente? | OS cancella | privato | +|:----------------------------------------------------------- |:--------------------------- |:----:|:------------:|:-----------:|:-------:| +| `File:///accounts/1000/AppData/ < id app > /` | applicationStorageDirectory | r | N/A | N/A | Sì | +|    `app/native` | applicationDirectory | r | N/A | N/A | Sì | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | No | Sì | Sì | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Sì | No | Sì | +| `File:///accounts/1000/Removable/sdcard` | externalRemovableDirectory | r/w | Sì | No | No | +| `File:///accounts/1000/Shared` | sharedDirectory | r/w | Sì | No | No | + +*Nota*: quando l'applicazione viene distribuita a lavorare perimetrale, tutti i percorsi sono relativi a /accounts/1000-enterprise. + +## Stranezze Android + +### Posizione di archiviazione persistente Android + +Ci sono più percorsi validi per memorizzare i file persistenti su un dispositivo Android. Vedi [questa pagina](http://developer.android.com/guide/topics/data/data-storage.html) per un'ampia discussione delle varie possibilità. + +Versioni precedenti del plugin avrebbe scelto il percorso dei file temporanei e permanenti su avvio, in base se il dispositivo ha sostenuto che la scheda SD (o partizione storage equivalente) è stato montato. Se è stata montata sulla scheda SD o una partizione di storage interno grande era disponibile (come sui dispositivi Nexus,) allora saranno memorizzati i file persistenti nella radice di quello spazio. Questo significava che tutte le apps di Cordova poteva vedere tutti i file disponibili sulla carta. + +Se la scheda SD non era disponibile, poi versioni precedenti vuoi memorizzare dati sotto `/data/data/`, che isola i apps da altro, ma può ancora causa dati da condividere tra gli utenti. + +Ora è possibile scegliere se memorizzare i file nel percorso di archiviazione di file interno o utilizzando la logica precedente, con una preferenza nel file `config. xml` dell'applicazione. Per fare questo, aggiungere una di queste due linee al `file config. xml`: + + + + + + +Senza questa linea, il File del plugin utilizzerà la `Compatibility` come predefinito. Se è presente un tag di preferenza e non è uno di questi valori, l'applicazione non si avvia. + +Se l'applicazione è stato spedito in precedenza agli utenti, utilizzando un vecchio (pre-1.0) versione di questo plugin e ha i file memorizzati nel filesystem persistente, allora si dovrebbe impostare la preferenza di `Compatibility`. La posizione su "Interno" di commutazione significherebbe che gli utenti esistenti che aggiornare la loro applicazione potrebbero essere Impossibile accedere ai loro file precedentemente memorizzati, a seconda del loro dispositivo. + +Se l'applicazione è nuova, o ha mai precedentemente memorizzati i file nel filesystem persistente, è generalmente consigliato l'impostazione `Internal`. + +### Operazioni ricorsive lento per /android_asset + +L'elencazione delle directory asset è veramente lento su Android. È possibile velocizzare e fino anche se, con l'aggiunta di `src/android/build-extras.gradle` alla radice del tuo progetto android (richiede anche cordova-android@4.0.0 o superiore). + +## iOS stranezze + + * `cordova.file.applicationStorageDirectory`è di sola lettura; tentativo di memorizzare i file all'interno della directory radice avrà esito negativo. Utilizzare uno degli altri `cordova.file.*` proprietà definite per iOS (solo `applicationDirectory` e `applicationStorageDirectory` sono di sola lettura). + * `FileReader.readAsText(blob, encoding)` + * Il `encoding` parametro non è supportato, e codifica UTF-8 è sempre attivo. + +### posizione di archiviazione persistente di iOS + +Ci sono due percorsi validi per memorizzare i file persistenti su un dispositivo iOS: la directory documenti e la biblioteca. Precedenti versioni del plugin archiviati solo mai persistenti file nella directory documenti. Questo ha avuto l'effetto collaterale di tutti i file di un'applicazione che rende visibili in iTunes, che era spesso involontaria, soprattutto per le applicazioni che gestiscono un sacco di piccoli file, piuttosto che produrre documenti completi per l'esportazione, che è la destinazione della directory. + +Ora è possibile scegliere se memorizzare i file nella directory di libreria, con una preferenza nel file `config. xml` dell'applicazione o documenti. Per fare questo, aggiungere una di queste due linee al `file config. xml`: + + + + + + +Senza questa linea, il File del plugin utilizzerà la `Compatibility` come predefinito. Se è presente un tag di preferenza e non è uno di questi valori, l'applicazione non si avvia. + +Se l'applicazione è stato spedito in precedenza agli utenti, utilizzando un vecchio (pre-1.0) versione di questo plugin e ha i file memorizzati nel filesystem persistente, allora si dovrebbe impostare la preferenza di `Compatibility`. La posizione di commutazione alla `libreria` significherebbe che gli utenti esistenti che aggiornare la loro applicazione è in grado di accedere ai loro file precedentemente memorizzati. + +Se l'applicazione è nuova, o ha mai precedentemente memorizzati i file nel filesystem persistente, è generalmente consigliato l'impostazione della `Library`. + +## Firefox OS stranezze + +L'API di sistema del File non è supportato nativamente dal sistema operativo Firefox e viene implementato come uno spessore in cima indexedDB. + + * Non manca quando si rimuove le directory non vuota + * Non supporta i metadati per le directory + * Metodi `copyTo` e `moveTo` non supporta le directory + +Sono supportati i seguenti percorsi di dati: * `applicationDirectory` - utilizza `xhr` per ottenere i file locali che sono confezionati con l'app. *`dataDirectory` - per i file di dati persistenti app specifiche. *`cacheDirectory` - file memorizzati nella cache che dovrebbe sopravvivere si riavvia app (applicazioni non devono basarsi sull'OS di eliminare i file qui). + +## Stranezze browser + +### Stranezze e osservazioni comuni + + * Ogni browser utilizza il proprio filesystem in modalità sandbox. IE e Firefox utilizzare IndexedDB come base. Tutti i browser utilizzano barra come separatore di directory in un percorso. + * Le voci di directory devono essere creato successivamente. Ad esempio, la chiamata `fs.root.getDirectory (' dir1/dir2 ', {create:true}, successCallback, errorCallback)` non riuscirà se non esistesse dir1. + * Il plugin richiede autorizzazione utente per utilizzare un archivio permanente presso il primo avvio dell'applicazione. + * Plugin supporta `cdvfile://localhost` (risorse locali) solo. Cioè risorse esterne non sono supportate tramite `cdvfile`. + * Il plugin non segue ["Limitazioni di denominazione 8.3 File sistema API"](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions). + * BLOB e File' `close` la funzione non è supportata. + * `FileSaver` e `BlobBuilder` non sono supportati da questo plugin e non hanno gli stub. + * Il plugin non supporta `requestAllFileSystems`. Questa funzione manca anche nelle specifiche. + * Entrate nella directory non verranno rimossi se si utilizza `create: true` bandiera per directory esistente. + * Non sono supportati i file creati tramite il costruttore. È invece necessario utilizzare il metodo entry.file. + * Ogni browser utilizza la propria forma per riferimenti URL blob. + * `readAsDataURL` funzione è supportata, ma il mediatype in Chrome dipende dall'estensione di voce, mediatype in IE è sempre vuota (che è lo stesso come `text-plain` secondo la specifica), il mediatype in Firefox è sempre `application/octet-stream`. Ad esempio, se il contenuto è `abcdefg` quindi Firefox restituisce `dati: applicazione / octet-stream; base64, YWJjZGVmZw = =`, cioè restituisce `dati:; base64, YWJjZGVmZw = =`, Chrome restituisce `dati: < mediatype a seconda dell'estensione del nome della voce >; base64, YWJjZGVmZw = =`. + * `toInternalURL` restituisce il percorso in forma `file:///persistent/path/to/entry` (Firefox, IE). Chrome restituisce il percorso nella forma `cdvfile://localhost/persistent/file`. + +### Stranezze di cromo + + * Cromo filesystem non è subito pronto dopo evento ready dispositivo. Come soluzione alternativa, è possibile iscriversi all'evento `filePluginIsReady`. Esempio: + +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` + +È possibile utilizzare la funzione `window.isFilePluginReadyRaised` per verificare se evento già è stato generato. -quote di filesystem TEMPORARY e PERSISTENT window.requestFileSystem non sono limitate in Chrome. -Per aumentare la memoria persistente in Chrome è necessario chiamare il metodo `window.initPersistentFileSystem`. Quota di archiviazione persistente è di 5 MB per impostazione predefinita. -Chrome richiede `-consentire-file-accesso-da-file` eseguire argomento a supporto API tramite protocollo `file:///`. -`File` oggetto non cambierà se si utilizza il flag `{create:true}` quando ottenendo un' esistente `entrata`. -eventi `cancelable` è impostata su true in Chrome. Ciò è in contrasto con la [specifica](http://dev.w3.org/2009/dap/file-system/file-writer.html). -funzione `toURL` Chrome restituisce `filesystem:`-premessi percorso a seconda dell'applicazione host. Ad esempio, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -`toURL` risultato di funzione non contiene una barra finale in caso di voce di directory. Chrome risolve le directory con gli URL slash-trainati però correttamente. -`resolveLocalFileSystemURL` metodo richiede in ingresso `url` avere il prefisso del `file System`. Ad esempio, il parametro `url` per `resolveLocalFileSystemURL` dovrebbe essere nella forma `filesystem:file:///persistent/somefile.txt` in contrasto con la forma `file:///persistent/somefile.txt` in Android. -Obsoleto `toNativeURL` funzione non è supportata e non dispone di uno stub. -funzione `setMetadata` non è indicato nelle specifiche e non supportato. -INVALID_MODIFICATION_ERR (codice: 9) viene generata invece di SYNTAX_ERR(code: 8) su richiesta di un filesystem inesistente. -INVALID_MODIFICATION_ERR (codice: 9) viene generata invece di PATH_EXISTS_ERR(code: 12) sul tentativo di creare esclusivamente un file o una directory, che esiste già. -INVALID_MODIFICATION_ERR (codice: 9) viene generata invece di NO_MODIFICATION_ALLOWED_ERR(code: 6) sul tentativo di chiamare removeRecursively su file system root. -INVALID_MODIFICATION_ERR (codice: 9) viene generata invece di NOT_FOUND_ERR(code: 1) sul tentativo moveTo directory che non esiste. + +### Stranezze impl IndexedDB-basato (Firefox e IE) + + * `.` e `.` non sono supportati. + * IE non supporta `file:///`-modalità; modalità solo ospitata è supportato (http://localhost:xxxx). + * Dimensione filesystem Firefox non è limitata, ma ogni estensione 50MB sarà richiesta un'autorizzazione dell'utente. IE10 consente fino a 10mb di combinato AppCache e IndexedDB utilizzato nell'implementazione del filesystem senza chiedere conferma, una volta premuto quel livello che vi verrà chiesto se si desidera consentire ad essere aumentata fino a un max di 250 mb per ogni sito. Quindi la `size` parametro per la funzione `requestFileSystem` non influisce il filesystem in Firefox e IE. + * `readAsBinaryString` funzione non è indicato nelle specifiche e non supportati in IE e non dispone di uno stub. + * `file.Type` è sempre null. + * Non è necessario creare la voce utilizzando il risultato del callback istanza DirectoryEntry che è stato eliminato. In caso contrario, si otterrà una 'voce di sospensione'. + * Prima è possibile leggere un file che è stato appena scritto è necessario ottenere una nuova istanza di questo file. + * supporta la funzione `setMetadata`, che non è indicato nelle specifiche `modificationTime` cambiamento di campo solo. + * funzioni `copyTo` e `moveTo` non supporta le directory. + * Le directory metadati non sono supportato. + * Sia Entry.remove e directoryEntry.removeRecursively non fallire quando si rimuove le directory non vuota - directory da rimuovere vengono pulite invece insieme al contenuto. + * `abort` e `truncate` le funzioni non sono supportate. + * non vengono generati eventi di progresso. Ad esempio, questo gestore verrà non eseguito: + +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## Note di aggiornamento + +In v 1.0.0 di questo plugin, le strutture `FileEntry` e `DirectoryEntry` sono cambiati, per essere più in linea con le specifiche pubblicate. + +Versioni precedenti (pre-1.0.0) del plugin archiviati il dispositivo-assoluto--percorso del file nella proprietà `fullPath` di oggetti della `voce`. In genere questi percorsi si sarebbe simile + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Questi percorsi sono stati anche restituiti dal metodo `toURL()` degli oggetti `Entry`. + +Con v 1.0.0, l'attributo `fullPath` è il percorso del file, *rispetto alla radice del filesystem HTML*. Così, i percorsi sopra sarebbe ora sia rappresentato da un oggetto `FileEntry` con un `fullPath` di + + /path/to/file + + +Se l'applicazione funziona con dispositivo-assoluto-percorsi, e precedentemente recuperato quei percorsi attraverso la proprietà `fullPath` della `voce` oggetti, è necessario aggiornare il codice per utilizzare `entry.toURL()` invece. + +Per indietro la compatibilità, il metodo `resolveLocalFileSystemURL()` verrà accettare un dispositivo-assoluto-percorso e restituirà un oggetto di `entrata` corrispondente ad essa, fintanto che il file esiste all'interno del filesystem la `temporanea` o `permanente`. + +Questo particolare è stato un problema con il plugin di trasferimento File, che in precedenza utilizzati percorsi-dispositivo-assoluto (e ancora può accoglierli). Esso è stato aggiornato per funzionare correttamente con gli URL di FileSystem, così sostituendo `entry.fullPath` con `entry.toURL()` dovrebbe risolvere eventuali problemi ottenendo quel plugin per lavorare con i file nel dispositivo. + +In v 1.1.0 il valore restituito di `toURL()` è stato cambiato (vedere \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) per restituire un URL assoluto 'file://'. ove possibile. Per assicurare un ' cdvfile:'-URL, è possibile utilizzare `toInternalURL()` ora. Questo metodo restituirà ora filesystem URL del modulo + + cdvfile://localhost/persistent/path/to/file + + +che può essere utilizzato per identificare univocamente il file. + +## Elenco dei codici di errore e significati + +Quando viene generato un errore, uno dei seguenti codici da utilizzare. + +| Codice | Costante | +| ------:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Configurare il Plugin (opzionale) + +Il set di filesystem disponibili può essere configurato per ogni piattaforma. Sia iOS che Android riconoscere un Tag nel `file config. xml` che nomina il filesystem per essere installato. Per impostazione predefinita, tutte le radici del file system sono abilitate. + + + + + +### Android + + * `files`: directory di archiviazione di file interno dell'applicazione + * `files-external`: directory di archiviazione dell'applicazione file esterno + * `sdcard`: la directory di archiviazione di file esterni globale (questa è la radice della scheda SD, se uno è installato). È necessario disporre dell'autorizzazione `android.permission.WRITE_EXTERNAL_STORAGE` utilizzare questo. + * `cache`: la cache interna directory applicazione + * `cache-external`: directory di cache esterna dell'applicazione + * `root`: il dispositivo intero filesystem + +Android supporta anche un filesystem speciale denominato "documenti", che rappresenta una sottodirectory "/ documenti /" all'interno del filesystem "files". + +### iOS + + * `library`: la directory dell'applicazione libreria + * `documents`: la directory dell'applicazione documenti + * `cache`: la Cache directory applicazione + * `bundle`: bundle dell'applicazione; la posizione dell'app sul disco (sola lettura) + * `root`: il dispositivo intero filesystem + +Per impostazione predefinita, la directory di libreria e documenti può essere sincronizzata a iCloud. È anche possibile richiedere due filesystem aggiuntivi, `library-nosync` e `documents-nosync`, che rappresentano una speciale directory non sincronizzati entro il `/Library` o filesystem `/Documents`. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/it/index.md b/mobile/plugins/cordova-plugin-file/doc/it/index.md new file mode 100644 index 0000000..f3cd731 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/it/index.md @@ -0,0 +1,338 @@ + + +# cordova-plugin-file + +Questo plugin implementa un API File permettendo l'accesso di lettura/scrittura ai file che risiedono sul dispositivo. + +Questo plugin si basa su diverse specifiche, tra cui: The HTML5 File API + +Le directory (ormai defunta) e il sistema delle estensioni più recenti: anche se la maggior parte del codice plugin è stato scritto quando una spec precedenti era corrente: + +Implementa inoltre FileWriter spec: + +Per l'utilizzo, fare riferimento a HTML5 Rocks' eccellente [articolo FileSystem.][1] + + [1]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +Per una panoramica delle altre opzioni di archiviazione, consultare [Guida di archiviazione di Cordova][2]. + + [2]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +Questo plugin definisce oggetto global `cordova.file`. + +Anche se in ambito globale, non è disponibile fino a dopo l'evento `deviceready`. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## Installazione + + cordova plugin add cordova-plugin-file + + +## Piattaforme supportate + +* Amazon fuoco OS +* Android +* BlackBerry 10 +* Firefox OS +* iOS +* Windows Phone 7 e 8 * +* Windows 8 * +* Browser + +* *Queste piattaforme non supportano `FileReader.readAsArrayBuffer` né `FileWriter.write(blob)`.* + +## Dove memorizzare i file + +A partire dalla v 1.2.0, vengono forniti gli URL per le directory importanti file di sistema. Ogni URL è nella forma *file:///path/to/spot/* e può essere convertito in un `DirectoryEntry` utilizzando `window.resolveLocalFileSystemURL()`. + +* `cordova.file.applicationDirectory`-Sola lettura directory dove è installato l'applicazione. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.applicationStorageDirectory`-Directory radice di sandbox dell'applicazione; su iOS questa posizione è in sola lettura (ma sottodirectory specifiche [come `/Documents` ] sono di sola lettura). Tutti i dati contenuti all'interno è privato all'app. ( *iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.dataDirectory`-Archiviazione dati persistente e privati nella sandbox dell'applicazione utilizzando la memoria interna (su Android, se è necessario utilizzare la memoria esterna, utilizzare `.externalDataDirectory` ). IOS, questa directory non è sincronizzata con iCloud (utilizzare `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.cacheDirectory`-Directory per i file memorizzati nella cache di dati o qualsiasi file che app possibile ricreare facilmente. L'OS può eliminare questi file quando il dispositivo viene eseguito basso sull'archiviazione, tuttavia, apps non deve basarsi sul sistema operativo per cancellare i file qui. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.externalApplicationStorageDirectory`-Spazio applicazione su storage esterno. (*Android*) + +* `cordova.file.externalDataDirectory`-Dove mettere i file di dati specifico app su storage esterno. (*Android*) + +* `cordova.file.externalCacheDirectory`-Cache applicazione su storage esterno. (*Android*) + +* `cordova.file.externalRootDirectory`-Radice di archiviazione esterna (scheda SD). (*Android*, *BlackBerry, 10*) + +* `cordova.file.tempDirectory`-Temp directory che l'OS è possibile cancellare a volontà. Non fare affidamento sul sistema operativo per cancellare questa directory; l'app deve sempre rimuovere file come applicabile. (*iOS*) + +* `cordova.file.syncedDataDirectory`-Contiene i file app specifiche che devono essere sincronizzati (per esempio a iCloud). (*iOS*) + +* `cordova.file.documentsDirectory`-I file privati per le app, ma che sono significativi per altre applicazioni (ad esempio i file di Office). (*iOS*) + +* `cordova.file.sharedDirectory`-File disponibili globalmente a tutte le applicazioni (*BlackBerry 10*) + +## Layout dei file di sistema + +Anche se tecnicamente un dettaglio di implementazione, può essere molto utile per conoscere come le proprietà `cordova.file.*` mappa di percorsi fisici su un dispositivo reale. + +### iOS File sistema Layout + +| Percorso dispositivo | `Cordova.file.*` | `iosExtraFileSystems` | r/w? | persistente? | OS cancella | sincronizzazione | privato | +|:-------------------------------------------- |:--------------------------- |:--------------------- |:----:|:------------:|:-----------:|:----------------:|:-------:| +| `/ var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N/A | N/A | N/A | Sì | +|    `appname.app/` | applicationDirectory | bundle | r | N/A | N/A | N/A | Sì | +|       `www/` | - | - | r | N/A | N/A | N/A | Sì | +|    `Documents/` | documentsDirectory | documenti | r/w | Sì | No | Sì | Sì | +|       `NoCloud/` | - | nosync-documenti | r/w | Sì | No | No | Sì | +|    `Library` | - | libreria | r/w | Sì | No | Sì? | Sì | +|       `NoCloud/` | dataDirectory | nosync-libreria | r/w | Sì | No | No | Sì | +|       `Cloud/` | syncedDataDirectory | - | r/w | Sì | No | Sì | Sì | +|       `Caches/` | cacheDirectory | cache | r/w | Sì * | Sì * * *| | No | Sì | +|    `tmp/` | tempDirectory | - | r/w | No * * | Sì * * *| | No | Sì | + +* File persistono attraverso riavvii app e aggiornamenti, ma questa directory può essere azzerata ogni volta che desideri l'OS. L'app dovrebbe essere in grado di ricreare qualsiasi contenuto che potrebbe essere eliminato. + +* * File può persistere attraverso app riavvii, ma non fare affidamento su questo comportamento. I file non sono garantiti a persistere attraverso gli aggiornamenti. L'app deve rimuovere i file dalla directory quando è applicabile, come il sistema operativo non garantisce quando (o anche se) questi file vengono rimossi. + +* * *| Il sistema operativo può cancellare il contenuto di questa directory ogni volta che si sente è necessario, ma non fare affidamento su questo. Si dovrebbe cancellare questa directory come adatto per l'applicazione. + +### Layout sistema Android File + +| Percorso dispositivo | `Cordova.file.*` | `AndroidExtraFileSystems` | r/w? | persistente? | OS cancella | privato | +|:--------------------------------- |:----------------------------------- |:------------------------- |:----:|:------------:|:-----------:|:-------:| +| `File:///android_asset/` | applicationDirectory | | r | N/A | N/A | Sì | +| `< app-id > /dati/dati / /` | applicationStorageDirectory | - | r/w | N/A | N/A | Sì | +|    `cache` | cacheDirectory | cache | r/w | Sì | Sì * | Sì | +|    `files` | dataDirectory | file | r/w | Sì | No | Sì | +|       `Documents` | | documenti | r/w | Sì | No | Sì | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | Sì | No | No | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Sì | No | No | +|       `cache` | externalCacheDirectry | cache-esterno | r/w | Sì | No * * | No | +|       `files` | externalDataDirectory | file-esterno | r/w | Sì | No | No | + +* Il sistema operativo può cancellare periodicamente questa directory, ma non fare affidamento su questo comportamento. Cancellare il contenuto di questa directory come adatto per l'applicazione. Il contenuto di questa directory dovrebbe un utente eliminare manualmente la cache, vengono rimossi. + +* * Il sistema operativo non cancella questa directory automaticamente; Tu sei responsabile per la gestione dei contenuti da soli. Il contenuto della directory dovrebbe l'utente eliminare manualmente la cache, vengono rimossi. + +**Nota**: se la memorizzazione esterna non può essere montato, le proprietà `cordova.file.external*` sono `null`. + +### BlackBerry 10 File sistema Layout + +| Percorso dispositivo | `Cordova.file.*` | r/w? | persistente? | OS cancella | privato | +|:--------------------------------------------------- |:--------------------------- |:----:|:------------:|:-----------:|:-------:| +| `File:///accounts/1000/AppData/ < id app > /` | applicationStorageDirectory | r | N/A | N/A | Sì | +|    `app/native` | applicationDirectory | r | N/A | N/A | Sì | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | No | Sì | Sì | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Sì | No | Sì | +| `File:///accounts/1000/Removable/sdcard` | externalRemovableDirectory | r/w | Sì | No | No | +| `File:///accounts/1000/Shared` | sharedDirectory | r/w | Sì | No | No | + +*Nota*: quando l'applicazione viene distribuita a lavorare perimetrale, tutti i percorsi sono relativi a /accounts/1000-enterprise. + +## Stranezze Android + +### Posizione di archiviazione persistente Android + +Ci sono più percorsi validi per memorizzare i file persistenti su un dispositivo Android. Vedi [questa pagina][3] per un'ampia discussione delle varie possibilità. + + [3]: http://developer.android.com/guide/topics/data/data-storage.html + +Versioni precedenti del plugin avrebbe scelto il percorso dei file temporanei e permanenti su avvio, in base se il dispositivo ha sostenuto che la scheda SD (o partizione storage equivalente) è stato montato. Se è stata montata sulla scheda SD o una partizione di storage interno grande era disponibile (come sui dispositivi Nexus,) allora saranno memorizzati i file persistenti nella radice di quello spazio. Questo significava che tutte le apps di Cordova poteva vedere tutti i file disponibili sulla carta. + +Se la scheda SD non era disponibile, poi versioni precedenti vuoi memorizzare dati sotto `/data/data/`, che isola i apps da altro, ma può ancora causa dati da condividere tra gli utenti. + +Ora è possibile scegliere se memorizzare i file nel percorso di archiviazione di file interno o utilizzando la logica precedente, con una preferenza nel file `config. xml` dell'applicazione. Per fare questo, aggiungere una di queste due linee al `file config. xml`: + + + + + + +Senza questa linea, il File del plugin utilizzerà la `Compatibility` come predefinito. Se è presente un tag di preferenza e non è uno di questi valori, l'applicazione non si avvia. + +Se l'applicazione è stato spedito in precedenza agli utenti, utilizzando un vecchio (pre-1.0) versione di questo plugin e ha i file memorizzati nel filesystem persistente, allora si dovrebbe impostare la preferenza di `Compatibility`. La posizione su "Interno" di commutazione significherebbe che gli utenti esistenti che aggiornare la loro applicazione potrebbero essere Impossibile accedere ai loro file precedentemente memorizzati, a seconda del loro dispositivo. + +Se l'applicazione è nuova, o ha mai precedentemente memorizzati i file nel filesystem persistente, è generalmente consigliato l'impostazione `Internal`. + +## iOS stranezze + +* `cordova.file.applicationStorageDirectory`è di sola lettura; tentativo di memorizzare i file all'interno della directory radice avrà esito negativo. Utilizzare uno degli altri `cordova.file.*` proprietà definite per iOS (solo `applicationDirectory` e `applicationStorageDirectory` sono di sola lettura). +* `FileReader.readAsText(blob, encoding)` + * Il `encoding` parametro non è supportato, e codifica UTF-8 è sempre attivo. + +### posizione di archiviazione persistente di iOS + +Ci sono due percorsi validi per memorizzare i file persistenti su un dispositivo iOS: la directory documenti e la biblioteca. Precedenti versioni del plugin archiviati solo mai persistenti file nella directory documenti. Questo ha avuto l'effetto collaterale di tutti i file di un'applicazione che rende visibili in iTunes, che era spesso involontaria, soprattutto per le applicazioni che gestiscono un sacco di piccoli file, piuttosto che produrre documenti completi per l'esportazione, che è la destinazione della directory. + +Ora è possibile scegliere se memorizzare i file nella directory di libreria, con una preferenza nel file `config. xml` dell'applicazione o documenti. Per fare questo, aggiungere una di queste due linee al `file config. xml`: + + + + + + +Senza questa linea, il File del plugin utilizzerà la `Compatibility` come predefinito. Se è presente un tag di preferenza e non è uno di questi valori, l'applicazione non si avvia. + +Se l'applicazione è stato spedito in precedenza agli utenti, utilizzando un vecchio (pre-1.0) versione di questo plugin e ha i file memorizzati nel filesystem persistente, allora si dovrebbe impostare la preferenza di `Compatibility`. La posizione di commutazione alla `libreria` significherebbe che gli utenti esistenti che aggiornare la loro applicazione è in grado di accedere ai loro file precedentemente memorizzati. + +Se l'applicazione è nuova, o ha mai precedentemente memorizzati i file nel filesystem persistente, è generalmente consigliato l'impostazione della `Library`. + +## Firefox OS stranezze + +L'API di sistema del File non è supportato nativamente dal sistema operativo Firefox e viene implementato come uno spessore in cima indexedDB. + +* Non manca quando si rimuove le directory non vuota +* Non supporta i metadati per le directory +* Metodi `copyTo` e `moveTo` non supporta le directory + +Sono supportati i seguenti percorsi di dati: * `applicationDirectory` - utilizza `xhr` per ottenere i file locali che sono confezionati con l'app. *`dataDirectory` - per i file di dati persistenti app specifiche. *`cacheDirectory` - file memorizzati nella cache che dovrebbe sopravvivere si riavvia app (applicazioni non devono basarsi sull'OS di eliminare i file qui). + +## Stranezze browser + +### Stranezze e osservazioni comuni + +* Ogni browser utilizza il proprio filesystem in modalità sandbox. IE e Firefox utilizzare IndexedDB come base. Tutti i browser utilizzano barra come separatore di directory in un percorso. +* Le voci di directory devono essere creato successivamente. Ad esempio, la chiamata `fs.root.getDirectory (' dir1/dir2 ', {create:true}, successCallback, errorCallback)` non riuscirà se non esistesse dir1. +* Il plugin richiede autorizzazione utente per utilizzare un archivio permanente presso il primo avvio dell'applicazione. +* Plugin supporta `cdvfile://localhost` (risorse locali) solo. Cioè risorse esterne non sono supportate tramite `cdvfile`. +* Il plugin non segue ["Limitazioni di denominazione 8.3 File sistema API"][4]. +* BLOB e File' `close` la funzione non è supportata. +* `FileSaver` e `BlobBuilder` non sono supportati da questo plugin e non hanno gli stub. +* Il plugin non supporta `requestAllFileSystems`. Questa funzione manca anche nelle specifiche. +* Entrate nella directory non verranno rimossi se si utilizza `create: true` bandiera per directory esistente. +* Non sono supportati i file creati tramite il costruttore. È invece necessario utilizzare il metodo entry.file. +* Ogni browser utilizza la propria forma per riferimenti URL blob. +* `readAsDataURL` funzione è supportata, ma il mediatype in Chrome dipende dall'estensione di voce, mediatype in IE è sempre vuota (che è lo stesso come `text-plain` secondo la specifica), il mediatype in Firefox è sempre `application/octet-stream`. Ad esempio, se il contenuto è `abcdefg` quindi Firefox restituisce `dati: applicazione / octet-stream; base64, YWJjZGVmZw = =`, cioè restituisce `dati:; base64, YWJjZGVmZw = =`, Chrome restituisce `dati: < mediatype a seconda dell'estensione del nome della voce >; base64, YWJjZGVmZw = =`. +* `toInternalURL` restituisce il percorso in forma `file:///persistent/path/to/entry` (Firefox, IE). Chrome restituisce il percorso nella forma `cdvfile://localhost/persistent/file`. + + [4]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions + +### Stranezze di cromo + +* Cromo filesystem non è subito pronto dopo evento ready dispositivo. Come soluzione alternativa, è possibile iscriversi all'evento `filePluginIsReady`. Esempio: + + javascript + window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); + + +È possibile utilizzare la funzione `window.isFilePluginReadyRaised` per verificare se evento già è stato generato. -quote di filesystem TEMPORARY e PERSISTENT window.requestFileSystem non sono limitate in Chrome. -Per aumentare la memoria persistente in Chrome è necessario chiamare il metodo `window.initPersistentFileSystem`. Quota di archiviazione persistente è di 5 MB per impostazione predefinita. -Chrome richiede `-consentire-file-accesso-da-file` eseguire argomento a supporto API tramite protocollo `file:///`. -`File` oggetto non cambierà se si utilizza il flag `{create:true}` quando ottenendo un' esistente `entrata`. -eventi `cancelable` è impostata su true in Chrome. Ciò è in contrasto con la [specifica][5]. -funzione `toURL` Chrome restituisce `filesystem:`-premessi percorso a seconda dell'applicazione host. Ad esempio, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -`toURL` risultato di funzione non contiene una barra finale in caso di voce di directory. Chrome risolve le directory con gli URL slash-trainati però correttamente. -`resolveLocalFileSystemURL` metodo richiede in ingresso `url` avere il prefisso del `file System`. Ad esempio, il parametro `url` per `resolveLocalFileSystemURL` dovrebbe essere nella forma `filesystem:file:///persistent/somefile.txt` in contrasto con la forma `file:///persistent/somefile.txt` in Android. -Obsoleto `toNativeURL` funzione non è supportata e non dispone di uno stub. -funzione `setMetadata` non è indicato nelle specifiche e non supportato. -INVALID_MODIFICATION_ERR (codice: 9) viene generata invece di SYNTAX_ERR(code: 8) su richiesta di un filesystem inesistente. -INVALID_MODIFICATION_ERR (codice: 9) viene generata invece di PATH_EXISTS_ERR(code: 12) sul tentativo di creare esclusivamente un file o una directory, che esiste già. -INVALID_MODIFICATION_ERR (codice: 9) viene generata invece di NO_MODIFICATION_ALLOWED_ERR(code: 6) sul tentativo di chiamare removeRecursively su file system root. -INVALID_MODIFICATION_ERR (codice: 9) viene generata invece di NOT_FOUND_ERR(code: 1) sul tentativo moveTo directory che non esiste. + + [5]: http://dev.w3.org/2009/dap/file-system/file-writer.html + +### Stranezze impl IndexedDB-basato (Firefox e IE) + +* `.` e `.` non sono supportati. +* IE non supporta `file:///`-modalità; modalità solo ospitata è supportato (http://localhost:xxxx). +* Dimensione filesystem Firefox non è limitata, ma ogni estensione 50MB sarà richiesta un'autorizzazione dell'utente. IE10 consente fino a 10mb di combinato AppCache e IndexedDB utilizzato nell'implementazione del filesystem senza chiedere conferma, una volta premuto quel livello che vi verrà chiesto se si desidera consentire ad essere aumentata fino a un max di 250 mb per ogni sito. Quindi la `size` parametro per la funzione `requestFileSystem` non influisce il filesystem in Firefox e IE. +* `readAsBinaryString` funzione non è indicato nelle specifiche e non supportati in IE e non dispone di uno stub. +* `file.Type` è sempre null. +* Non è necessario creare la voce utilizzando il risultato del callback istanza DirectoryEntry che è stato eliminato. In caso contrario, si otterrà una 'voce di sospensione'. +* Prima è possibile leggere un file che è stato appena scritto è necessario ottenere una nuova istanza di questo file. +* supporta la funzione `setMetadata`, che non è indicato nelle specifiche `modificationTime` cambiamento di campo solo. +* funzioni `copyTo` e `moveTo` non supporta le directory. +* Le directory metadati non sono supportato. +* Sia Entry.remove e directoryEntry.removeRecursively non fallire quando si rimuove le directory non vuota - directory da rimuovere vengono pulite invece insieme al contenuto. +* `abort` e `truncate` le funzioni non sono supportate. +* non vengono generati eventi di progresso. Ad esempio, questo gestore verrà non eseguito: + + javascript + writer.onprogress = function() { /*commands*/ }; + + +## Note di aggiornamento + +In v 1.0.0 di questo plugin, le strutture `FileEntry` e `DirectoryEntry` sono cambiati, per essere più in linea con le specifiche pubblicate. + +Versioni precedenti (pre-1.0.0) del plugin archiviati il dispositivo-assoluto--percorso del file nella proprietà `fullPath` di oggetti della `voce`. In genere questi percorsi si sarebbe simile + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Questi percorsi sono stati anche restituiti dal metodo `toURL()` degli oggetti `Entry`. + +Con v 1.0.0, l'attributo `fullPath` è il percorso del file, *rispetto alla radice del filesystem HTML*. Così, i percorsi sopra sarebbe ora sia rappresentato da un oggetto `FileEntry` con un `fullPath` di + + /path/to/file + + +Se l'applicazione funziona con dispositivo-assoluto-percorsi, e precedentemente recuperato quei percorsi attraverso la proprietà `fullPath` della `voce` oggetti, è necessario aggiornare il codice per utilizzare `entry.toURL()` invece. + +Per indietro la compatibilità, il metodo `resolveLocalFileSystemURL()` verrà accettare un dispositivo-assoluto-percorso e restituirà un oggetto di `entrata` corrispondente ad essa, fintanto che il file esiste all'interno del filesystem la `temporanea` o `permanente`. + +Questo particolare è stato un problema con il plugin di trasferimento File, che in precedenza utilizzati percorsi-dispositivo-assoluto (e ancora può accoglierli). Esso è stato aggiornato per funzionare correttamente con gli URL di FileSystem, così sostituendo `entry.fullPath` con `entry.toURL()` dovrebbe risolvere eventuali problemi ottenendo quel plugin per lavorare con i file nel dispositivo. + +In v 1.1.0 il valore restituito di `toURL()` è stato cambiato (vedere \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) per restituire un URL assoluto 'file://'. ove possibile. Per assicurare un ' cdvfile:'-URL, è possibile utilizzare `toInternalURL()` ora. Questo metodo restituirà ora filesystem URL del modulo + + cdvfile://localhost/persistent/path/to/file + + +che può essere utilizzato per identificare univocamente il file. + +## Elenco dei codici di errore e significati + +Quando viene generato un errore, uno dei seguenti codici da utilizzare. + +| Codice | Costante | +| ------:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Configurare il Plugin (opzionale) + +Il set di filesystem disponibili può essere configurato per ogni piattaforma. Sia iOS che Android riconoscere un Tag nel `file config. xml` che nomina il filesystem per essere installato. Per impostazione predefinita, tutte le radici del file system sono abilitate. + + + + + +### Android + +* `files`: directory di archiviazione di file interno dell'applicazione +* `files-external`: directory di archiviazione dell'applicazione file esterno +* `sdcard`: la directory di archiviazione di file esterni globale (questa è la radice della scheda SD, se uno è installato). È necessario disporre dell'autorizzazione `android.permission.WRITE_EXTERNAL_STORAGE` utilizzare questo. +* `cache`: la cache interna directory applicazione +* `cache-external`: directory di cache esterna dell'applicazione +* `root`: il dispositivo intero filesystem + +Android supporta anche un filesystem speciale denominato "documenti", che rappresenta una sottodirectory "/ documenti /" all'interno del filesystem "files". + +### iOS + +* `library`: la directory dell'applicazione libreria +* `documents`: la directory dell'applicazione documenti +* `cache`: la Cache directory applicazione +* `bundle`: bundle dell'applicazione; la posizione dell'app sul disco (sola lettura) +* `root`: il dispositivo intero filesystem + +Per impostazione predefinita, la directory di libreria e documenti può essere sincronizzata a iCloud. È anche possibile richiedere due filesystem aggiuntivi, `library-nosync` e `documents-nosync`, che rappresentano una speciale directory non sincronizzati entro il `/Library` o filesystem `/Documents`. diff --git a/mobile/plugins/cordova-plugin-file/doc/it/plugins.md b/mobile/plugins/cordova-plugin-file/doc/it/plugins.md new file mode 100644 index 0000000..d3f1465 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/it/plugins.md @@ -0,0 +1,101 @@ + + +# Note per gli sviluppatori di plugin + +Queste note sono destinate principalmente per gli sviluppatori di Android e iOS che vogliono scrivere plugin quale interfaccia con il sistema di file utilizzando il File plugin. + +## Lavorando con URL di sistema file di Cordova + +Dalla versione 1.0.0, questo plugin ha utilizzato gli URL con un `cdvfile` schema per tutte le comunicazioni oltre il ponte, piuttosto che esporre i percorsi del file system di dispositivo raw a JavaScript. + +Sul lato JavaScript, questo significa che gli oggetti FileEntry e DirectoryEntry dispongano di un attributo fullPath che è relativo alla directory principale del sistema di file HTML. Se API JavaScript del vostro plugin accetta un oggetto FileEntry o DirectoryEntry, è necessario chiamare `.toURL()` su quell'oggetto prima di passarlo attraverso il ponte in codice nativo. + +### Conversione cdvfile: / / URL ai percorsi fileystem + +Plugin che hanno bisogno di scrivere il filesystem può essere necessario convertire un URL di sistema del file ricevuto in un percorso effettivo filesystem. Ci sono diversi modi di fare questo, a seconda della piattaforma nativa. + +È importante ricordare che non tutti i `cdvfile://` URL sono mappabili ai veri file sul dispositivo. Alcuni URL può riferirsi a beni sul dispositivo che non sono rappresentate da file, o possono anche fare riferimento a risorse remote. A causa di queste possibilità, plugin dovrebbe sempre verificare se ottengono un risultato significativo indietro quando si tenta di convertire gli URL in percorsi. + +#### Android + +Su Android, il metodo più semplice per convertire un `cdvfile://` URL a un percorso di file System è quello di utilizzare `org.apache.cordova.CordovaResourceApi` . `CordovaResourceApi`dispone di diversi metodi che è possono gestire `cdvfile://` URL: + + webView è un membro del Plugin classe CordovaResourceApi resourceApi = webView.getResourceApi(); + + Ottenere un URL file:/// che rappresenta questo file sul dispositivo, / / o lo stesso URL invariata se non può essere mappato a un file Uri fileURL = resourceApi.remapUri(Uri.parse(cdvfileURL)); + + +È anche possibile utilizzare direttamente il File plugin: + + importazione org.apache.cordova.file.FileUtils; + importazione org.apache.cordova.file.FileSystem; + importazione java.net.MalformedURLException; + + Ottenere il File plugin dal gestore plugin FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + Dato un URL, ottenere un percorso per esso prova {String path = filePlugin.filesystemPathForURL(cdvfileURL);}} catch (MalformedURLException e) {/ / l'url del file System non è stato riconosciuto} + + +Convertire da un percorso a un `cdvfile://` URL: + + importazione org.apache.cordova.file.LocalFilesystemURL; + + Ottenere un oggetto LocalFilesystemURL per un percorso di dispositivo, / / oppure null se non può essere rappresentata come un URL di cdvfile. + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path); + Ottenere la rappresentazione di stringa dell'URL oggetto String cdvfileURL = url.toString(); + + +Se il vostro plugin crea un file e si desidera restituire un oggetto FileEntry per esso, utilizzare il File plugin: + + Restituire una struttura JSON appropriato per restituire a JavaScript, / / o null se questo file non è rappresentabile come un URL di cdvfile. + Voce di JSONObject = filePlugin.getEntryForFile(file); + + +#### iOS + +Cordova su iOS non utilizza lo stesso `CordovaResourceApi` concetto come Android. Su iOS, si dovrebbe utilizzare il plugin File per convertire tra URL e percorsi di file System. + + Ottenere un oggetto CDVFilesystem URL da una stringa CDVFilesystemURL * url = [CDVFilesystemURL fileSystemURLWithString:cdvfileURL]; + Ottenere un percorso per l'oggetto URL, o zero se non può essere mappato a un percorso di file NSString * = [filePlugin filesystemPathForURL:url]; + + + Ottenere un oggetto CDVFilesystem URL per un percorso di dispositivo, o / / nullo se non può essere rappresentata come un URL di cdvfile. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + Ottenere la rappresentazione di stringa dell'URL oggetto NSString * cdvfileURL = [absoluteString url]; + + +Se il vostro plugin crea un file e si desidera restituire un oggetto FileEntry per esso, utilizzare il File plugin: + + Ottenere un oggetto CDVFilesystem URL per un percorso di dispositivo, o / / nullo se non può essere rappresentata come un URL di cdvfile. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + Ottenere una struttura per tornare alla voce JavaScript NSDictionary * = [filePlugin makeEntryForLocalURL:url] + + +#### JavaScript + +In JavaScript, per ottenere un `cdvfile://` URL da un oggetto FileEntry o DirectoryEntry, semplicemente chiamare `.toURL()` su di esso: + + var cdvfileURL = entry.toURL(); + + +Nei gestori di risposta del plugin, per convertire da una struttura FileEntry restituita in un oggetto reale di voce, il codice del gestore dovrebbe importare il File plugin e creare un nuovo oggetto: + + creare la voce appropriata a voce oggetto var; + Se (entryStruct.isDirectory) {voce = new DirectoryEntry (entryStruct.name, entryStruct.fullPath, nuovo FileSystem(entryStruct.filesystemName));} altro {voce = FileEntry nuovo (entryStruct.name, entryStruct.fullPath, nuovo FileSystem(entryStruct.filesystemName));} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/ja/README.md b/mobile/plugins/cordova-plugin-file/doc/ja/README.md new file mode 100644 index 0000000..96e8ff0 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/ja/README.md @@ -0,0 +1,335 @@ + + +# cordova-plugin-file + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg)](https://travis-ci.org/apache/cordova-plugin-file) + +このプラグインは、デバイス上のファイルへの読み取り/書き込みアクセスを許可するファイル API を実装します。 + +このプラグインを含む、いくつかの仕様に基づいています:、HTML5 File API の + +(今は亡き) ディレクトリとシステムは、最新の拡張機能: プラグインのコードのほとんどはときに、以前の仕様に書かれていたが現在は: + +FileWriter 仕様も実装しています: + +使用法を参照してください HTML5 岩 ' 優秀な[ファイルシステム記事](http://www.html5rocks.com/en/tutorials/file/filesystem/)。 + +他のストレージ オプションの概要については、コルドバの[ストレージ ・ ガイド](http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html)を参照してください。. + +このプラグインでは、グローバル `cordova.file` オブジェクトを定義します。 + +グローバル スコープではあるがそれがないまで `deviceready` イベントの後です。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## インストール + + cordova plugin add cordova-plugin-file + + +## サポートされているプラットフォーム + + * アマゾン火 OS + * アンドロイド + * ブラックベリー 10 + * Firefox の OS + * iOS + * Windows Phone 7 と 8 * + * Windows 8 * + * Windows* + * ブラウザー + +\* *These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`.* + +## ファイルを保存する場所 + +V1.2.0、現在重要なファイル システム ディレクトリへの Url を提供しています。 各 URL はフォーム *file:///path/to/spot/* で、`window.resolveLocalFileSystemURL()` を使用する `DirectoryEntry` に変換することができます。. + + * `cordova.file.applicationDirectory`-読み取り専用のディレクトリは、アプリケーションがインストールされています。(*iOS*、*アンドロイド*、*ブラックベリー 10*) + + * `cordova.file.applicationStorageDirectory`-アプリケーションのサンド ボックス; のルート ディレクトリiOS でこの場所が読み取り専用 (特定のサブディレクトリが [のような `/Documents` ] は、読み取り/書き込み)。 内に含まれるすべてのデータは、アプリケーションにプライベートです。 ( *iOS*、*アンドロイド*、*ブラックベリー 10*) + + * `cordova.file.dataDirectory`内部メモリを使用して、アプリケーションのサンド ボックス内で永続なプライベート データ ストレージ (外部メモリを使用する必要がある場合使用して Android 上で `.externalDataDirectory` )。 IOS は、このディレクトリは iCloud と同期されません (使用する `.syncedDataDirectory` )。 (*iOS*、*アンドロイド*、*ブラックベリー 10*) + + * `cordova.file.cacheDirectory`-キャッシュされたデータ ファイルやアプリに簡単に再作成できる任意のファイルのディレクトリ。 ストレージ デバイスが不足したときに、OS がこれらのファイルを削除可能性があります、それにもかかわらず、アプリはここにファイルを削除する OS に依存しないでください。 (*iOS*、*アンドロイド*、*ブラックベリー 10*) + + * `cordova.file.externalApplicationStorageDirectory`外部ストレージのアプリケーション領域。(*アンドロイド*) + + * `cordova.file.externalDataDirectory`-外部ストレージ上のアプリ固有のデータ ファイルを配置する場所。(*アンドロイド*) + + * `cordova.file.externalCacheDirectory`外部ストレージにアプリケーション キャッシュ。(*アンドロイド*) + + * `cordova.file.externalRootDirectory`-外部ストレージ (SD カード) ルート。(*アンドロイド*、*ブラックベリー 10*) + + * `cordova.file.tempDirectory`-OS をクリアすることができます temp ディレクトリが。 このディレクトリ; オフに OS に依存しません。アプリが常に該当するファイルを削除します。 (*iOS*) + + * `cordova.file.syncedDataDirectory`-(例えば iCloud) に同期する必要がありますアプリケーション固有のファイルを保持します。(*iOS*) + + * `cordova.file.documentsDirectory`-ファイル、アプリケーションにプライベートは他のアプリケーション (Office ファイルなど) を意味です。(*iOS*) + + * `cordova.file.sharedDirectory`すべてのアプリケーション (*ブラックベリー 10*にグローバルに使用できるファイル) + +## ファイル ・ システム ・ レイアウト + +技術的に実装の詳細、非常にどのように `cordova.file.*` プロパティは、実際のデバイス上の物理パスにマップを知っておくと便利することができます。 + +### iOS ファイル システムのレイアウト + +| デバイス ・ パス | `cordova.file.*` | `iosExtraFileSystems` | r/w ですか? | 永続的なですか? | OS を消去します | 同期 | プライベート | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:--------:|:---------:|:------------:|:------:|:------:| +| `/var/モバイル/アプリケーション/< UUID >/` | applicationStorageDirectory | - | r | N/A | N/A | N/A | はい | +|    `appname.app/` | ディレクトリ | バンドル | r | N/A | N/A | N/A | はい | +|       `www/` | - | - | r | N/A | N/A | N/A | はい | +|    `Documents/` | documentsDirectory | ドキュメント | r/w | はい | いいえ | はい | はい | +|       `NoCloud/` | - | ドキュメント nosync | r/w | はい | いいえ | いいえ | はい | +|    `Library` | - | ライブラリ | r/w | はい | いいえ | はいですか? | はい | +|       `NoCloud/` | dataDirectory | ライブラリ nosync | r/w | はい | いいえ | いいえ | はい | +|       `Cloud/` | syncedDataDirectory | - | r/w | はい | いいえ | はい | はい | +|       `Caches/` | cacheDirectory | キャッシュ | r/w | はい * | はい**\* | いいえ | はい | +|    `tmp/` | tempDirectory | - | r/w | いいえ** | はい**\* | いいえ | はい | + +\ * アプリ再起動やアップグレード、永続化ファイルしますが、OS を希望するたびに、このディレクトリを削除することができます。アプリは削除可能性があります任意のコンテンツを再現することができるはず。 + +**ファイルはアプリ再起動の間続くことがありますが、この動作に依存しないでください。 ファイルは、更新を維持するは保証されません。 アプリが該当する場合このディレクトリからファイルを削除する必要があります、これらのファイルが削除されるとき (または場合でも)、OS は保証しません。 + +**\ * OS はそれ、必要だと感じているときにこのディレクトリの内容を消去可能性があります、これに依存しないようにします。 この適切なディレクトリに、アプリケーションをオフにする必要があります。 + +### 人造人間ファイル ・ システム ・ レイアウト + +| デバイス ・ パス | `cordova.file.*` | `AndroidExtraFileSystems` | r/w ですか? | 永続的なですか? | OS を消去します | プライベート | +|:------------------------------------------------ |:----------------------------------- |:------------------------- |:--------:|:--------:|:---------:|:------:| +| `file:///android_asset/` | ディレクトリ | | r | N/A | N/A | はい | +| `/データ/データ/< app id >/` | applicationStorageDirectory | - | r/w | N/A | N/A | はい | +|    `cache` | cacheDirectory | キャッシュ | r/w | はい | はい\ * | はい | +|    `files` | dataDirectory | ファイル | r/w | はい | いいえ | はい | +|       `Documents` | | ドキュメント | r/w | はい | いいえ | はい | +| `< sd カード >/` | externalRootDirectory | sd カード | r/w | はい | いいえ | いいえ | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | はい | いいえ | いいえ | +|       `cache` | externalCacheDirectry | 外部キャッシュ | r/w | はい | いいえ** | いいえ | +|       `files` | externalDataDirectory | 外部ファイル | r/w | はい | いいえ | いいえ | + +\ * OS は定期的にこのディレクトリを消去可能性がありますが、この動作に依存しないでください。 アプリケーションの必要に応じてこのディレクトリの内容をオフにします。 ユーザーは手動でキャッシュを削除する必要があります、このディレクトリの内容が削除されます。 + +** OS はこのディレクトリを自動的にはクリアされません内容を自分で管理する責任があります。 ユーザは手動でキャッシュを消去する必要があります、ディレクトリの内容が削除されます。 + +**注**: 外部記憶装置をマウントできない場合は、`cordova.file.external*` プロパティを `null`. + +### ブラックベリー 10 ファイル ・ システム ・ レイアウト + +| デバイス ・ パス | `cordova.file.*` | r/w ですか? | 永続的なですか? | OS を消去します | プライベート | +|:----------------------------------------------------------- |:--------------------------- |:--------:|:--------:|:---------:|:------:| +| `file:///accounts/1000/appdata/< app id >/` | applicationStorageDirectory | r | N/A | N/A | はい | +|    `app/native` | ディレクトリ | r | N/A | N/A | はい | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | いいえ | はい | はい | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | はい | いいえ | はい | +| `file:///accounts/1000/removable/sdcard` | externalRemovableDirectory | r/w | はい | いいえ | いいえ | +| `file:///accounts/1000/shared` | sharedDirectory | r/w | はい | いいえ | いいえ | + +*注*: すべてのパスは/accounts/1000-enterprise 基準に境界を動作するようにアプリケーションを展開するとき。 + +## Android の癖 + +### Android の永続的なストレージの場所 + +Android のデバイスに永続的なファイルを格納する複数の有効な場所があります。 さまざまな可能性について広範な議論のための [このページ](http://developer.android.com/guide/topics/data/data-storage.html) を参照してください。 + +以前のバージョンのプラグインは、デバイスの SD カード (または同等のストレージ パーティション) マウントされていたと主張したかどうかに基づいて、起動時に一時と永続的なファイルの場所を選ぶでしょう。 SD カードがマウントされている場合、または大規模な内部ストレージ パーティションが利用可能な場合 (ようネクサス デバイス上) し、永続的なファイルは、その領域のルートに格納されます。 これはすべての Cordova アプリ見ることができる利用可能なファイルのすべてのカードに意味しました。 + +SD カードがない場合、以前のバージョンがデータを格納する `/data/data/`、お互いからアプリを分離するが、まだ原因可能性がありますユーザー間で共有するデータ。 + +内部ファイルの保存場所やアプリケーションの `config.xml` ファイルに優先順位を持つ以前のロジックを使用してファイルを保存するかどうかを選択することが可能です今。 これを行うに、`config.xml` に次の 2 行のいずれかを追加します。 + + + + + + +この行がなければファイル プラグインはデフォルトとして `Compatibility` を使用します。優先タグが存在し、これらの値の 1 つではない場合、アプリケーションは起動しません。 + +アプリケーションは、ユーザーに以前出荷されている場合、古い (前 1.0) を使用して、このプラグインのバージョンし、永続的なファイルシステムに保存されているファイルには `Compatibility` を設定する必要があります。 自分のアプリケーションをアップグレードする既存のユーザーを彼らの装置によって、以前に保存されたファイルにアクセスすることができることがあることを意味する「内部」に場所をスイッチングします。 + +アプリケーションは、新しい、または永続的なファイルシステムにファイルが格納され以前は決して場合、`内部` 設定一般的に推奨されます。 + +### /Android_asset の低速の再帰的な操作 + +アセット ディレクトリの一覧表示は、人造人間本当に遅いです。 それをスピードアップすることができます`src/android/build-extras.gradle`を android プロジェクトのルートに追加することによって、最大 (また cordova-android@4.0.0 が必要ですまたはそれ以上)。 + +## iOS の癖 + + * `cordova.file.applicationStorageDirectory`読み取り専用;ルート ディレクトリ内のファイルを保存しようは失敗します。 他の 1 つを使用して `cordova.file.*` iOS のため定義されているプロパティ (のみ `applicationDirectory` と `applicationStorageDirectory` は読み取り専用)。 + * `FileReader.readAsText(blob, encoding)` + * `encoding`パラメーターはサポートされていませんし、utf-8 エンコーディングが常に有効です。 + +### iOS の永続的なストレージの場所 + +IOS デバイスに永続的なファイルを格納する 2 つの有効な場所がある: ドキュメントとライブラリのディレクトリ。 プラグインの以前のバージョンは、唯一のこれまでドキュメント ディレクトリに永続的なファイルを格納されます。 これは、ディレクトリの目的は、輸出のための完全なドキュメントを作成するのではなくなかったがしばしば意図されていたり、特に多数の小さいファイルを処理するアプリケーションの場合、iTunes に表示されているすべてのアプリケーションのファイルを作るの副作用があった。 + +ドキュメントまたはアプリケーションの `config.xml` ファイルに優先順位のライブラリ ディレクトリにファイルを保存するかどうかを選択することが可能です今。 これを行うに、`config.xml` に次の 2 行のいずれかを追加します。 + + + + + + +この行がなければファイル プラグインはデフォルトとして `Compatibility` を使用します。優先タグが存在し、これらの値の 1 つではない場合、アプリケーションは起動しません。 + +アプリケーションは、ユーザーに以前出荷されている場合、古い (前 1.0) を使用して、このプラグインのバージョンし、永続的なファイルシステムに保存されているファイルには `Compatibility` を設定する必要があります。 自分のアプリケーションをアップグレードする既存のユーザーを以前に保存されたファイルにアクセスすることができるだろうことを意味する `Library` に場所をスイッチングします。 + +アプリケーションは、新しい、または永続的なファイルシステムにファイルが格納され以前は決して場合、`Library` 設定一般的に推奨されます。 + +## Firefox OS 癖 + +ファイル システム API Firefox OS でネイティブ サポートされていないと、indexedDB の上にシムとして実装されています。 + + * 空でないディレクトリを削除するときに失敗しません + * ディレクトリのメタデータをサポートしていません + * 方法 `copyTo` と `moveTo` ディレクトリをサポートしていません + +次のデータ パスがサポートされています: * `applicationDirectory` - `xhr` を使用して、アプリケーションと共にパッケージ化されるローカル ファイルを取得します。 * `dataDirectory` - 永続的なアプリケーション固有のデータ ファイル。 * `cacheDirectory` - アプリケーションの再起動後も維持する必要がありますキャッシュ ファイル (アプリはここにファイルを削除する OS に依存しないでください)。 + +## ブラウザーの癖 + +### 共通の癖と発言 + + * 各ブラウザーはサンド ボックス化されたファイルシステムを使用します。IE と Firefox IndexedDB をベースとして使用します。すべてのブラウザーは、パスにディレクトリの区切り記号としてスラッシュを使用します。 + * ディレクトリ エントリは連続して作成されなければなりません。 たとえば、コール `fs.root.getDirectory ('dir1 dir2'、{create:true}、successCallback、解り)` dir1 が存在しなかった場合は失敗します。 + * プラグインは、永続的なストレージ アプリケーションの最初の起動時に使用するユーザーのアクセス許可を要求します。 + * プラグインは、`cdvfile://localhost` (ローカル リソース) をサポートしているだけです。すなわち外部リソースは、`cdvfile` を介してサポートされていません. + * プラグインに [制限」のファイル システム API の 8.3 命名規則](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions) に従っていません。. + * Blob およびファイル ' `close` 関数はサポートされていません。 + * `FileSaver` と `BlobBuilder` このプラグインでサポートされていないスタブを持っていません。 + * プラグインは、`requestAllFileSystems` をサポートしません。この関数は、仕様で行方不明にも。 + * ディレクトリ内のエントリを使用すると削除されません `create: true` 既存ディレクトリのフラグ。 + * コンス トラクターで作成されたファイルはサポートされていません。代わりに entry.file メソッドを使用する必要があります。 + * 各ブラウザーは blob URL 参照の独自のフォームを使用します。 + * `readAsDataURL` 関数はサポートされてがクロムメッキで mediatype エントリ名の拡張子によって異なります、IE でメディアの種類は、常に空 (`text-plain` に従って、仕様と同じである)、Firefox でメディアの種類は常に `アプリケーションまたはオクテット-ストリーム`。 たとえば、コンテンツが場合 `abcdefg` し Firefox を返します `データ: アプリケーション/オクテット ストリーム、base64、YWJjZGVmZw = =`、すなわちを返します `データ:; base64、YWJjZGVmZw = =`、クロムを返します `データ: < エントリ名の拡張子によって mediatype >; base64、YWJjZGVmZw = =`. + * `toInternalURL` フォーム `file:///persistent/path/to/entry` (Firefox、IE) のパスを返します。 クロムの `cdvfile://localhost/persistent/file` フォームのパスを返します. + +### クロムの癖 + + * デバイスの準備ができているイベント後クローム ファイルシステムはすぐに準備ができています。回避策としては `filePluginIsReady` イベントにサブスクライブできます。例: + +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` + +`window.isFilePluginReadyRaised` 関数を使用して、イベントが既に発生したかどうかを確認できます。 -Chrome に window.requestFileSystem 一時と永続的なファイル ・ システムのクォータの制限はありません。 -クロム内の永続ストレージを増加する `window.initPersistentFileSystem` メソッドを呼び出す必要があります。 永続的な記憶域のクォータは、既定では 5 MB です。 クロムが必要です `--許可-ファイル-アクセス--ファイルから` `file:///` プロトコル経由でサポート API に引数を実行します。 -`ファイル` オブジェクト フラグを使用する場合ない変更されます `{create:true}` 既存の `エントリ` を取得するとき。 -イベント `cancelable` プロパティを設定するクロムの場合は true。 これは [仕様](http://dev.w3.org/2009/dap/file-system/file-writer.html) に反して。 -クロムメッキで `網` 関数を返します `ファイルシステム:`-アプリケーションのホストによってパスのプレフィックスします。 たとえば、`filesystem:file:///persistent/somefile.txt`、`filesystem:http://localhost:8080/persistent/somefile.txt`。 -`toURL` の関数の結果にはディレクトリ エントリ場合末尾にスラッシュが含まれていません。 クロムは、スラッシュ後塵 url を持つディレクトリが正しく解決されるも。 -`resolveLocalFileSystemURL` メソッドは、受信 `url` が `ファイルシステム` のプレフィックスが必要です。 たとえば、`resolveLocalFileSystemURL` の `url` パラメーター フォーム `filesystem:file:///persistent/somefile.txt` で人造人間フォーム `file:///persistent/somefile.txt` とは対照的にする必要があります。 -廃止された `toNativeURL` 関数はサポートされていません、スタブはありません。 -`setMetadata` 関数は、仕様に記載されていないありサポートされていません。 -INVALID_MODIFICATION_ERR (コード: 9) の代わりにスローされた SYNTAX_ERR(code: 8) の非実在しないファイルシステムの依頼を。 -INVALID_MODIFICATION_ERR (コード: 9) の代わりにスローされた PATH_EXISTS_ERR(code: 12)、排他的なファイルまたはディレクトリを作成しようとするが既に存在します。 -INVALID_MODIFICATION_ERR (コード: 9) の代わりにスローされた NO_MODIFICATION_ALLOWED_ERR(code: 6) ルート ・ ファイル ・ システムで removeRecursively を呼び出すをしようとして。 -INVALID_MODIFICATION_ERR (コード: 9) の代わりにスローされた NOT_FOUND_ERR(code: 1) [moveto] ディレクトリが存在しないをしようとして。 + +### IndexedDB ベース インプレ癖 (Firefox と IE) + + * `.` `です。` はサポートされていません。 + * IE は `file:///` をサポートしていません-モード;ホスト モードのみがサポートされている (http://localhost:xxxx) です。 + * Firefox のファイルシステムのサイズは無制限ですが各 50 MB の拡張機能がユーザーのアクセス許可を要求します。 IE10 は最大 10 mb の複合 AppCache と IndexedDB を求めず、サイトごとに 250 mb の最大値まで増加を許可するかどうかをたずねられますそのレベルに当ればファイルシステムの実装で使用することができます。 `RequestFileSystem` 関数の `size` パラメーターは、Firefox と IE のファイルシステムには影響しません。 + * `readAsBinaryString` 関数の仕様に記載されていない、IE でサポートされていないと、スタブを持っていません。 + * `file.type` は、常に null です。 + * 削除された DirectoryEntry インスタンスのコールバックの結果を使用してエントリを作成しないでください。それ以外の場合は、'ハンギングのエントリ' が表示されます。 + * ちょうど書かれていた、ファイルを読むことができます前にこのファイルの新しいインスタンスを取得する必要があります。 + * `setMetadata` 関数は、仕様に記載されていない `modificationTime` フィールド変更のみをサポートします。 + * `copyTo` と `moveTo` 関数ディレクトリをサポートしていません。 + * ディレクトリのメタデータはサポートされていません。 + * 両方の Entry.remove と directoryEntry.removeRecursively は空でないディレクトリを削除するときを失敗しない - 削除されるディレクトリ コンテンツと共にを掃除している代わりに。 + * `abort` し、`truncate` 機能はサポートされていません。 + * 進行状況イベントは起動しません。たとえば、このハンドラーがない実行されます。 + +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## ノートをアップグレードします。 + +このプラグインのデベロッパー、公開された仕様に合うように、`認証` と `DirectoryEntry` の構造が変更されました。 + +プラグインの前 (pre 1.0.0) バージョンはデバイス絶対ファイル場所 `エントリ` オブジェクトの `fullPath` プロパティに格納されます。これらのパスはようになります通常 + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +これらのパスはまた `Entry` オブジェクトの `toURL()` メソッドによって返されます。 + +デベロッパー、`fullPath` 属性は *HTML ファイルシステムのルートに対する相対パス* のファイルへのパス。 したがって、上記のパスは今両方の `fullPath` と `FileEntry` オブジェクトで表される + + /path/to/file + + +デバイス絶対パスとアプリケーション動作以前 `Entry` オブジェクトの `fullPath` プロパティを使用してこれらのパスを取得した場合は、代わりに `entry.toURL()` を使用するコードを更新する必要があります。 + +下位互換性、`resolveLocalFileSystemURL()` メソッドは、デバイス絶対パスを受け入れるし、は、`TEMPORARY` または `PERSISTENT` ファイル ・ システム内でそのファイルが存在する限り、それに対応する `Entry` オブジェクトを返します。 + +これは特に以前デバイス絶対パスを使用してファイル転送のプラグインで問題となっている (そしてまだそれらを受け入れることができます)。 それがデバイス上のファイルで動作するプラグインを得る問題を解決する必要があります `entry.toURL()` で `entry.fullPath` を置き換えるので、ファイルシステムの Url で正常に動作にアップデートされました。 + +V1.1.0 の `toURL()` の戻り値に変更されました (\[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394) を参照) を絶対 'file://' で始まる URL を返します。 可能な限り。 確保するために、' cdvfile:'-`toInternalURL()` を今すぐ使用できます URL。 このメソッドは、フォームのファイルシステムの Url を返します今 + + cdvfile://localhost/persistent/path/to/file + + +これはファイルを一意に識別するために使用できます。 + +## エラー コードと意味のリスト + +エラーがスローされると、次のコードのいずれかが使用されます。 + +| コード | 定数 | +| ---:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## (省略可能) プラグインを構成します。 + +利用可能なファイルシステムのセットは構成されたプラットフォームをすることができます。IOS と Android の両方を認識します。 タグ `config.xml` をインストールするファイルシステムの名前します。既定では、すべてのファイル システムのルートが有効になります。 + + + + + +### アンドロイド + + * `files`: アプリケーションの内部ファイルのストレージ ディレクトリ + * `files-external`: アプリケーションの外部のファイルのストレージ ディレクトリ + * `sdcard`:、グローバル外部ストレージ ディレクトリをファイル (これは SD カードのルートがインストールされている場合)。 これを使用するには、`android.permission.WRITE_EXTERNAL_STORAGE` 権限が必要です。 + * `cache`: アプリケーションの内部キャッシュ ディレクトリ + * `cache-external`: 外部キャッシュのアプリケーションのディレクトリ + * `root`: デバイス全体のファイルシステム + +アンドロイドを「ファイル」ファイルシステム内の"ドキュメント/"サブディレクトリを表す"ドキュメント"という名前の特殊なファイルシステムもサポートしています。 + +### iOS + + * `library`: ライブラリのアプリケーションのディレクトリ + * `documents`: ドキュメントのアプリケーションのディレクトリ + * `cache`: キャッシュのアプリケーションのディレクトリ + * `bundle`: アプリケーションバンドル;アプリ自体 (読み取りのみ) ディスク上の場所 + * `root`: デバイス全体のファイルシステム + +既定では、ライブラリとドキュメント ディレクトリを iCloud に同期できます。 2 つの追加のファイルシステム、`library-nosync` および `documents-nosync` を表す、特別な非同期ディレクトリ内を要求することもできます、`/Library` または `Documents/` ファイルシステム。 \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/ja/index.md b/mobile/plugins/cordova-plugin-file/doc/ja/index.md new file mode 100644 index 0000000..57fb7d2 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/ja/index.md @@ -0,0 +1,338 @@ + + +# cordova-plugin-file + +このプラグインは、デバイス上のファイルへの読み取り/書き込みアクセスを許可するファイル API を実装します。 + +このプラグインを含む、いくつかの仕様に基づいています:、HTML5 File API の + +(今は亡き) ディレクトリとシステムは、最新の拡張機能: プラグインのコードのほとんどはときに、以前の仕様に書かれていたが現在は: + +FileWriter 仕様も実装しています: + +使用法を参照してください HTML5 岩 ' 優秀な[ファイルシステム記事][1]。 + + [1]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +他のストレージ オプションの概要については、コルドバの[ストレージ ・ ガイド][2]を参照してください。. + + [2]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +このプラグインでは、グローバル `cordova.file` オブジェクトを定義します。 + +グローバル スコープではあるがそれがないまで `deviceready` イベントの後です。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## インストール + + cordova plugin add cordova-plugin-file + + +## サポートされているプラットフォーム + +* アマゾン火 OS +* アンドロイド +* ブラックベリー 10 +* Firefox の OS +* iOS +* Windows Phone 7 と 8 * +* Windows 8 * +* ブラウザー + +* *`FileReader.readAsArrayBuffer` も `FileWriter.write(blob)` もこれらのプラットフォームはサポートしていません*。 + +## ファイルを保存する場所 + +V1.2.0、現在重要なファイル システム ディレクトリへの Url を提供しています。 各 URL はフォーム *file:///path/to/spot/* で、`window.resolveLocalFileSystemURL()` を使用する `DirectoryEntry` に変換することができます。. + +* `cordova.file.applicationDirectory`-読み取り専用のディレクトリは、アプリケーションがインストールされています。(*iOS*、*アンドロイド*、*ブラックベリー 10*) + +* `cordova.file.applicationStorageDirectory`-アプリケーションのサンド ボックス; のルート ディレクトリiOS でこの場所が読み取り専用 (特定のサブディレクトリが [のような `/Documents` ] は、読み取り/書き込み)。 内に含まれるすべてのデータは、アプリケーションにプライベートです。 ( *iOS*、*アンドロイド*、*ブラックベリー 10*) + +* `cordova.file.dataDirectory`内部メモリを使用して、アプリケーションのサンド ボックス内で永続なプライベート データ ストレージ (外部メモリを使用する必要がある場合使用して Android 上で `.externalDataDirectory` )。 IOS は、このディレクトリは iCloud と同期されません (使用する `.syncedDataDirectory` )。 (*iOS*、*アンドロイド*、*ブラックベリー 10*) + +* `cordova.file.cacheDirectory`-キャッシュされたデータ ファイルやアプリに簡単に再作成できる任意のファイルのディレクトリ。 ストレージ デバイスが不足したときに、OS がこれらのファイルを削除可能性があります、それにもかかわらず、アプリはここにファイルを削除する OS に依存しないでください。 (*iOS*、*アンドロイド*、*ブラックベリー 10*) + +* `cordova.file.externalApplicationStorageDirectory`外部ストレージのアプリケーション領域。(*アンドロイド*) + +* `cordova.file.externalDataDirectory`-外部ストレージ上のアプリ固有のデータ ファイルを配置する場所。(*アンドロイド*) + +* `cordova.file.externalCacheDirectory`外部ストレージにアプリケーション キャッシュ。(*アンドロイド*) + +* `cordova.file.externalRootDirectory`-外部ストレージ (SD カード) ルート。(*アンドロイド*、*ブラックベリー 10*) + +* `cordova.file.tempDirectory`-OS をクリアすることができます temp ディレクトリが。 このディレクトリ; オフに OS に依存しません。アプリが常に該当するファイルを削除します。 (*iOS*) + +* `cordova.file.syncedDataDirectory`-(例えば iCloud) に同期する必要がありますアプリケーション固有のファイルを保持します。(*iOS*) + +* `cordova.file.documentsDirectory`-ファイル、アプリケーションにプライベートは他のアプリケーション (Office ファイルなど) を意味です。(*iOS*) + +* `cordova.file.sharedDirectory`すべてのアプリケーション (*ブラックベリー 10*にグローバルに使用できるファイル) + +## ファイル ・ システム ・ レイアウト + +技術的に実装の詳細、非常にどのように `cordova.file.*` プロパティは、実際のデバイス上の物理パスにマップを知っておくと便利することができます。 + +### iOS ファイル システムのレイアウト + +| デバイス ・ パス | `cordova.file.*` | `iosExtraFileSystems` | r/w ですか? | 永続的なですか? | OS を消去します | 同期 | プライベート | +|:------------------------------------ |:--------------------------- |:--------------------- |:--------:|:--------:|:----------:|:------:|:------:| +| `/var/モバイル/アプリケーション/< UUID >/` | applicationStorageDirectory | - | r | N/A | N/A | N/A | はい | +|    `appname.app/` | ディレクトリ | バンドル | r | N/A | N/A | N/A | はい | +|       `www/` | - | - | r | N/A | N/A | N/A | はい | +|    `Documents/` | documentsDirectory | ドキュメント | r/w | はい | いいえ | はい | はい | +|       `NoCloud/` | - | ドキュメント nosync | r/w | はい | いいえ | いいえ | はい | +|    `Library` | - | ライブラリ | r/w | はい | いいえ | はいですか? | はい | +|       `NoCloud/` | dataDirectory | ライブラリ nosync | r/w | はい | いいえ | いいえ | はい | +|       `Cloud/` | syncedDataDirectory | - | r/w | はい | いいえ | はい | はい | +|       `Caches/` | cacheDirectory | キャッシュ | r/w | はい * | はい * * *| | いいえ | はい | +|    `tmp/` | tempDirectory | - | r/w | いいえ * * | はい * * *| | いいえ | はい | + +* アプリを再起動し、アップグレードとの間でファイルを保持が、OS を希望するたびにこのディレクトリを削除することができます。アプリを削除可能性があります任意のコンテンツを再作成することができる必要があります。 + +* * ファイル アプリケーション再起動を渡って続くことがありますが、この動作に依存しないでください。 ファイルは、更新を維持するは保証されません。 アプリが該当する場合このディレクトリからファイルを削除する必要があります、これらのファイルが削除されるとき (または場合でも)、OS は保証しません。 + +* * *| OS はそれ、必要だと感じているときにこのディレクトリの内容を消去可能性がありますが、これに依存しません。 この適切なディレクトリに、アプリケーションをオフにする必要があります。 + +### 人造人間ファイル ・ システム ・ レイアウト + +| デバイス ・ パス | `cordova.file.*` | `AndroidExtraFileSystems` | r/w ですか? | 永続的なですか? | OS を消去します | プライベート | +|:--------------------------------- |:----------------------------------- |:------------------------- |:--------:|:--------:|:---------:|:------:| +| `file:///android_asset/` | ディレクトリ | | r | N/A | N/A | はい | +| `/データ/データ/< app id >/` | applicationStorageDirectory | - | r/w | N/A | N/A | はい | +|    `cache` | cacheDirectory | キャッシュ | r/w | はい | はい * | はい | +|    `files` | dataDirectory | ファイル | r/w | はい | いいえ | はい | +|       `Documents` | | ドキュメント | r/w | はい | いいえ | はい | +| `< sd カード >/` | externalRootDirectory | sd カード | r/w | はい | いいえ | いいえ | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | はい | いいえ | いいえ | +|       `cache` | externalCacheDirectry | 外部キャッシュ | r/w | はい | いいえ * * | いいえ | +|       `files` | externalDataDirectory | 外部ファイル | r/w | はい | いいえ | いいえ | + +* OS このディレクトリを定期的に消去可能性がありますが、この動作に依存しないでください。 アプリケーションの必要に応じてこのディレクトリの内容をオフにします。 ユーザーは手動でキャッシュを削除する必要があります、このディレクトリの内容が削除されます。 + +* * OS はこのディレクトリは自動的にクリアされません自分でコンテンツを管理するために責任があります。 ユーザは手動でキャッシュを消去する必要があります、ディレクトリの内容が削除されます。 + +**注**: 外部記憶装置をマウントできない場合は、`cordova.file.external*` プロパティを `null`. + +### ブラックベリー 10 ファイル ・ システム ・ レイアウト + +| デバイス ・ パス | `cordova.file.*` | r/w ですか? | 永続的なですか? | OS を消去します | プライベート | +|:------------------------------------------------- |:--------------------------- |:--------:|:--------:|:---------:|:------:| +| `file:///accounts/1000/appdata/< app id >/` | applicationStorageDirectory | r | N/A | N/A | はい | +|    `app/native` | ディレクトリ | r | N/A | N/A | はい | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | いいえ | はい | はい | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | はい | いいえ | はい | +| `file:///accounts/1000/removable/sdcard` | externalRemovableDirectory | r/w | はい | いいえ | いいえ | +| `file:///accounts/1000/shared` | sharedDirectory | r/w | はい | いいえ | いいえ | + +*注*: すべてのパスは/accounts/1000-enterprise 基準に境界を動作するようにアプリケーションを展開するとき。 + +## Android の癖 + +### Android の永続的なストレージの場所 + +Android のデバイスに永続的なファイルを格納する複数の有効な場所があります。 さまざまな可能性について広範な議論のための [このページ][3] を参照してください。 + + [3]: http://developer.android.com/guide/topics/data/data-storage.html + +以前のバージョンのプラグインは、デバイスの SD カード (または同等のストレージ パーティション) マウントされていたと主張したかどうかに基づいて、起動時に一時と永続的なファイルの場所を選ぶでしょう。 SD カードがマウントされている場合、または大規模な内部ストレージ パーティションが利用可能な場合 (ようネクサス デバイス上) し、永続的なファイルは、その領域のルートに格納されます。 これはすべての Cordova アプリ見ることができる利用可能なファイルのすべてのカードに意味しました。 + +SD カードがない場合、以前のバージョンがデータを格納する `/data/data/`、お互いからアプリを分離するが、まだ原因可能性がありますユーザー間で共有するデータ。 + +内部ファイルの保存場所やアプリケーションの `config.xml` ファイルに優先順位を持つ以前のロジックを使用してファイルを保存するかどうかを選択することが可能です今。 これを行うに、`config.xml` に次の 2 行のいずれかを追加します。 + + + + + + +この行がなければファイル プラグインはデフォルトとして `Compatibility` を使用します。優先タグが存在し、これらの値の 1 つではない場合、アプリケーションは起動しません。 + +アプリケーションは、ユーザーに以前出荷されている場合、古い (前 1.0) を使用して、このプラグインのバージョンし、永続的なファイルシステムに保存されているファイルには `Compatibility` を設定する必要があります。 自分のアプリケーションをアップグレードする既存のユーザーを彼らの装置によって、以前に保存されたファイルにアクセスすることができることがあることを意味する「内部」に場所をスイッチングします。 + +アプリケーションは、新しい、または永続的なファイルシステムにファイルが格納され以前は決して場合、`内部` 設定一般的に推奨されます。 + +## iOS の癖 + +* `cordova.file.applicationStorageDirectory`読み取り専用;ルート ディレクトリ内のファイルを保存しようは失敗します。 他の 1 つを使用して `cordova.file.*` iOS のため定義されているプロパティ (のみ `applicationDirectory` と `applicationStorageDirectory` は読み取り専用)。 +* `FileReader.readAsText(blob, encoding)` + * `encoding`パラメーターはサポートされていませんし、utf-8 エンコーディングが常に有効です。 + +### iOS の永続的なストレージの場所 + +IOS デバイスに永続的なファイルを格納する 2 つの有効な場所がある: ドキュメントとライブラリのディレクトリ。 プラグインの以前のバージョンは、唯一のこれまでドキュメント ディレクトリに永続的なファイルを格納されます。 これは、ディレクトリの目的は、輸出のための完全なドキュメントを作成するのではなくなかったがしばしば意図されていたり、特に多数の小さいファイルを処理するアプリケーションの場合、iTunes に表示されているすべてのアプリケーションのファイルを作るの副作用があった。 + +ドキュメントまたはアプリケーションの `config.xml` ファイルに優先順位のライブラリ ディレクトリにファイルを保存するかどうかを選択することが可能です今。 これを行うに、`config.xml` に次の 2 行のいずれかを追加します。 + + + + + + +この行がなければファイル プラグインはデフォルトとして `Compatibility` を使用します。優先タグが存在し、これらの値の 1 つではない場合、アプリケーションは起動しません。 + +アプリケーションは、ユーザーに以前出荷されている場合、古い (前 1.0) を使用して、このプラグインのバージョンし、永続的なファイルシステムに保存されているファイルには `Compatibility` を設定する必要があります。 自分のアプリケーションをアップグレードする既存のユーザーを以前に保存されたファイルにアクセスすることができるだろうことを意味する `Library` に場所をスイッチングします。 + +アプリケーションは、新しい、または永続的なファイルシステムにファイルが格納され以前は決して場合、`Library` 設定一般的に推奨されます。 + +## Firefox OS 癖 + +ファイル システム API Firefox OS でネイティブ サポートされていないと、indexedDB の上にシムとして実装されています。 + +* 空でないディレクトリを削除するときに失敗しません +* ディレクトリのメタデータをサポートしていません +* 方法 `copyTo` と `moveTo` ディレクトリをサポートしていません + +次のデータ パスがサポートされています: * `applicationDirectory` - `xhr` を使用して、アプリケーションと共にパッケージ化されるローカル ファイルを取得します。 * `dataDirectory` - 永続的なアプリケーション固有のデータ ファイル。 * `cacheDirectory` - アプリケーションの再起動後も維持する必要がありますキャッシュ ファイル (アプリはここにファイルを削除する OS に依存しないでください)。 + +## ブラウザーの癖 + +### 共通の癖と発言 + +* 各ブラウザーはサンド ボックス化されたファイルシステムを使用します。IE と Firefox IndexedDB をベースとして使用します。すべてのブラウザーは、パスにディレクトリの区切り記号としてスラッシュを使用します。 +* ディレクトリ エントリは連続して作成されなければなりません。 たとえば、コール `fs.root.getDirectory ('dir1 dir2'、{create:true}、successCallback、解り)` dir1 が存在しなかった場合は失敗します。 +* プラグインは、永続的なストレージ アプリケーションの最初の起動時に使用するユーザーのアクセス許可を要求します。 +* プラグインは、`cdvfile://localhost` (ローカル リソース) をサポートしているだけです。すなわち外部リソースは、`cdvfile` を介してサポートされていません. +* プラグインに [制限」のファイル システム API の 8.3 命名規則][4] に従っていません。. +* Blob およびファイル ' `close` 関数はサポートされていません。 +* `FileSaver` と `BlobBuilder` このプラグインでサポートされていないスタブを持っていません。 +* プラグインは、`requestAllFileSystems` をサポートしません。この関数は、仕様で行方不明にも。 +* ディレクトリ内のエントリを使用すると削除されません `create: true` 既存ディレクトリのフラグ。 +* コンス トラクターで作成されたファイルはサポートされていません。代わりに entry.file メソッドを使用する必要があります。 +* 各ブラウザーは blob URL 参照の独自のフォームを使用します。 +* `readAsDataURL` 関数はサポートされてがクロムメッキで mediatype エントリ名の拡張子によって異なります、IE でメディアの種類は、常に空 (`text-plain` に従って、仕様と同じである)、Firefox でメディアの種類は常に `アプリケーションまたはオクテット-ストリーム`。 たとえば、コンテンツが場合 `abcdefg` し Firefox を返します `データ: アプリケーション/オクテット ストリーム、base64、YWJjZGVmZw = =`、すなわちを返します `データ:; base64、YWJjZGVmZw = =`、クロムを返します `データ: < エントリ名の拡張子によって mediatype >; base64、YWJjZGVmZw = =`. +* `toInternalURL` フォーム `file:///persistent/path/to/entry` (Firefox、IE) のパスを返します。 クロムの `cdvfile://localhost/persistent/file` フォームのパスを返します. + + [4]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions + +### クロムの癖 + +* デバイスの準備ができているイベント後クローム ファイルシステムはすぐに準備ができています。回避策としては `filePluginIsReady` イベントにサブスクライブできます。例: + + javascript + window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); + + +`window.isFilePluginReadyRaised` 関数を使用して、イベントが既に発生したかどうかを確認できます。 -Chrome に window.requestFileSystem 一時と永続的なファイル ・ システムのクォータの制限はありません。 -クロム内の永続ストレージを増加する `window.initPersistentFileSystem` メソッドを呼び出す必要があります。 永続的な記憶域のクォータは、既定では 5 MB です。 クロムが必要です `--許可-ファイル-アクセス--ファイルから` `file:///` プロトコル経由でサポート API に引数を実行します。 -`ファイル` オブジェクト フラグを使用する場合ない変更されます `{create:true}` 既存の `エントリ` を取得するとき。 -イベント `cancelable` プロパティを設定するクロムの場合は true。 これは [仕様][5] に反して。 -クロムメッキで `網` 関数を返します `ファイルシステム:`-アプリケーションのホストによってパスのプレフィックスします。 たとえば、`filesystem:file:///persistent/somefile.txt`、`filesystem:http://localhost:8080/persistent/somefile.txt`。 -`toURL` の関数の結果にはディレクトリ エントリ場合末尾にスラッシュが含まれていません。 クロムは、スラッシュ後塵 url を持つディレクトリが正しく解決されるも。 -`resolveLocalFileSystemURL` メソッドは、受信 `url` が `ファイルシステム` のプレフィックスが必要です。 たとえば、`resolveLocalFileSystemURL` の `url` パラメーター フォーム `filesystem:file:///persistent/somefile.txt` で人造人間フォーム `file:///persistent/somefile.txt` とは対照的にする必要があります。 -廃止された `toNativeURL` 関数はサポートされていません、スタブはありません。 -`setMetadata` 関数は、仕様に記載されていないありサポートされていません。 -INVALID_MODIFICATION_ERR (コード: 9) の代わりにスローされた SYNTAX_ERR(code: 8) の非実在しないファイルシステムの依頼を。 -INVALID_MODIFICATION_ERR (コード: 9) の代わりにスローされた PATH_EXISTS_ERR(code: 12)、排他的なファイルまたはディレクトリを作成しようとするが既に存在します。 -INVALID_MODIFICATION_ERR (コード: 9) の代わりにスローされた NO_MODIFICATION_ALLOWED_ERR(code: 6) ルート ・ ファイル ・ システムで removeRecursively を呼び出すをしようとして。 -INVALID_MODIFICATION_ERR (コード: 9) の代わりにスローされた NOT_FOUND_ERR(code: 1) [moveto] ディレクトリが存在しないをしようとして。 + + [5]: http://dev.w3.org/2009/dap/file-system/file-writer.html + +### IndexedDB ベース インプレ癖 (Firefox と IE) + +* `.` `です。` はサポートされていません。 +* IE は `file:///` をサポートしていません-モード;ホスト モードのみがサポートされている (http://localhost:xxxx) です。 +* Firefox のファイルシステムのサイズは無制限ですが各 50 MB の拡張機能がユーザーのアクセス許可を要求します。 IE10 は最大 10 mb の複合 AppCache と IndexedDB を求めず、サイトごとに 250 mb の最大値まで増加を許可するかどうかをたずねられますそのレベルに当ればファイルシステムの実装で使用することができます。 `RequestFileSystem` 関数の `size` パラメーターは、Firefox と IE のファイルシステムには影響しません。 +* `readAsBinaryString` 関数の仕様に記載されていない、IE でサポートされていないと、スタブを持っていません。 +* `file.type` は、常に null です。 +* 削除された DirectoryEntry インスタンスのコールバックの結果を使用してエントリを作成しないでください。それ以外の場合は、'ハンギングのエントリ' が表示されます。 +* ちょうど書かれていた、ファイルを読むことができます前にこのファイルの新しいインスタンスを取得する必要があります。 +* `setMetadata` 関数は、仕様に記載されていない `modificationTime` フィールド変更のみをサポートします。 +* `copyTo` と `moveTo` 関数ディレクトリをサポートしていません。 +* ディレクトリのメタデータはサポートされていません。 +* 両方の Entry.remove と directoryEntry.removeRecursively は空でないディレクトリを削除するときを失敗しない - 削除されるディレクトリ コンテンツと共にを掃除している代わりに。 +* `abort` し、`truncate` 機能はサポートされていません。 +* 進行状況イベントは起動しません。たとえば、このハンドラーがない実行されます。 + + javascript + writer.onprogress = function() { /*commands*/ }; + + +## ノートをアップグレードします。 + +このプラグインのデベロッパー、公開された仕様に合うように、`認証` と `DirectoryEntry` の構造が変更されました。 + +プラグインの前 (pre 1.0.0) バージョンはデバイス絶対ファイル場所 `エントリ` オブジェクトの `fullPath` プロパティに格納されます。これらのパスはようになります通常 + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +これらのパスはまた `Entry` オブジェクトの `toURL()` メソッドによって返されます。 + +デベロッパー、`fullPath` 属性は *HTML ファイルシステムのルートに対する相対パス* のファイルへのパス。 したがって、上記のパスは今両方の `fullPath` と `FileEntry` オブジェクトで表される + + /path/to/file + + +デバイス絶対パスとアプリケーション動作以前 `Entry` オブジェクトの `fullPath` プロパティを使用してこれらのパスを取得した場合は、代わりに `entry.toURL()` を使用するコードを更新する必要があります。 + +下位互換性、`resolveLocalFileSystemURL()` メソッドは、デバイス絶対パスを受け入れるし、は、`TEMPORARY` または `PERSISTENT` ファイル ・ システム内でそのファイルが存在する限り、それに対応する `Entry` オブジェクトを返します。 + +これは特に以前デバイス絶対パスを使用してファイル転送のプラグインで問題となっている (そしてまだそれらを受け入れることができます)。 それがデバイス上のファイルで動作するプラグインを得る問題を解決する必要があります `entry.toURL()` で `entry.fullPath` を置き換えるので、ファイルシステムの Url で正常に動作にアップデートされました。 + +V1.1.0 の `toURL()` の戻り値に変更されました (\[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394) を参照) を絶対 'file://' で始まる URL を返します。 可能な限り。 確保するために、' cdvfile:'-`toInternalURL()` を今すぐ使用できます URL。 このメソッドは、フォームのファイルシステムの Url を返します今 + + cdvfile://localhost/persistent/path/to/file + + +これはファイルを一意に識別するために使用できます。 + +## エラー コードと意味のリスト + +エラーがスローされると、次のコードのいずれかが使用されます。 + +| コード | 定数 | +| ---:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## (省略可能) プラグインを構成します。 + +利用可能なファイルシステムのセットは構成されたプラットフォームをすることができます。IOS と Android の両方を認識します。 タグ `config.xml` をインストールするファイルシステムの名前します。既定では、すべてのファイル システムのルートが有効になります。 + + + + + +### アンドロイド + +* `files`: アプリケーションの内部ファイルのストレージ ディレクトリ +* `files-external`: アプリケーションの外部のファイルのストレージ ディレクトリ +* `sdcard`:、グローバル外部ストレージ ディレクトリをファイル (これは SD カードのルートがインストールされている場合)。 これを使用するには、`android.permission.WRITE_EXTERNAL_STORAGE` 権限が必要です。 +* `cache`: アプリケーションの内部キャッシュ ディレクトリ +* `cache-external`: 外部キャッシュのアプリケーションのディレクトリ +* `root`: デバイス全体のファイルシステム + +アンドロイドを「ファイル」ファイルシステム内の"ドキュメント/"サブディレクトリを表す"ドキュメント"という名前の特殊なファイルシステムもサポートしています。 + +### iOS + +* `library`: ライブラリのアプリケーションのディレクトリ +* `documents`: ドキュメントのアプリケーションのディレクトリ +* `cache`: キャッシュのアプリケーションのディレクトリ +* `bundle`: アプリケーションバンドル;アプリ自体 (読み取りのみ) ディスク上の場所 +* `root`: デバイス全体のファイルシステム + +既定では、ライブラリとドキュメント ディレクトリを iCloud に同期できます。 2 つの追加のファイルシステム、`library-nosync` および `documents-nosync` を表す、特別な非同期ディレクトリ内を要求することもできます、`/Library` または `Documents/` ファイルシステム。 diff --git a/mobile/plugins/cordova-plugin-file/doc/ja/plugins.md b/mobile/plugins/cordova-plugin-file/doc/ja/plugins.md new file mode 100644 index 0000000..c54aa78 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/ja/plugins.md @@ -0,0 +1,101 @@ + + +# プラグイン開発者のためのメモ + +これらのノートは主に Android と iOS 開発者インタ フェース ファイルのプラグインを使用してファイル システムでプラグインを書きたい人向け。 + +## コルドバのファイル システムの Url での作業 + +バージョン 1.0.0 では、以来、このプラグインを含む Url を使用する `cdvfile` JavaScript に raw デバイス ファイル システムのパスを公開するのではなく、橋の上のすべての通信方式します。 + +JavaScript 側では、これはファイルと DirectoryEntry オブジェクトに HTML ファイル システムのルートを基準として、fullPath 属性があることを意味します。 あなたのプラグインの JavaScript API がファイルまたは DirectoryEntry オブジェクトを受け入れる場合を呼び出す必要があります `.toURL()` 橋を渡ってそれをネイティブ コードに渡す前にそのオブジェクトの。 + +### Cdvfile に変換する://fileystem のパスに Url + +ファイルシステムへの書き込みする必要があるプラグインは、実際のファイルシステムの場所に受信したファイル システム URL に変換する必要があります。ネイティブ プラットフォームによって、これを行うための複数の方法があります。 + +それを覚えていることが重要ですすべて `cdvfile://` の Url がデバイス上の実際のファイルをマッピング可能な。 いくつかの Url は、ファイルでは表されないまたはリモート リソースを参照することができますもデバイス上の資産を参照できます。 これらの可能性のためのプラグインは、戻るときにパスに Url を変換しようとして、彼らは意味のある結果を得るかどうか常にテスト必要があります。 + +#### アンドロイド + +アンドロイド, に変換する最も簡単な方法で、 `cdvfile://` を使用するファイルシステムのパスに URL は `org.apache.cordova.CordovaResourceApi` 。 `CordovaResourceApi`扱うことができるいくつかの方法は、 `cdvfile://` の Url: + + webView プラグイン クラス CordovaResourceApi resourceApi のメンバーである = webView.getResourceApi()。 + + デバイスでこのファイルを表す file:///URL を取得//ファイル Uri fileURL にマップできない場合、同じ URL は変更されません = resourceApi.remapUri(Uri.parse(cdvfileURL)); + + +また、ファイルのプラグインを直接使用することが可能です。 + + インポート org.apache.cordova.file.FileUtils; + インポート org.apache.cordova.file.FileSystem; + インポート java.net.MalformedURLException; + + プラグイン マネージャーからファイルのプラグインを入手してコマンド filePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + それを試みるためにパスを取得 URL を指定すると、{文字列パス = filePlugin.filesystemPathForURL(cdvfileURL);} キャッチ (MalformedURLException e) {/ファイルシステムの url が認識されませんでした/} + + +パスから変換する、 `cdvfile://` URL: + + インポート org.apache.cordova.file.LocalFilesystemURL; + + デバイス ・ パスの LocalFilesystemURL オブジェクトを取得//cdvfile URL として表現できない場合は null。 + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path); + URL オブジェクトの文字列 cdvfileURL の文字列表現を取得する = url.toString(); + + +あなたのプラグインは、ファイルを作成しをファイル オブジェクトを返す場合、ファイルのプラグインを使用します。 + + JavaScript を返すときに適した JSON 構造を返す//このファイルは cdvfile URL として表現できない場合は null。 + JSONObject エントリ = filePlugin.getEntryForFile(file); + + +#### iOS + +IOS のコルドバは同じを使用しない `CordovaResourceApi` アンドロイドとしての概念。IOS では、Url とファイルシステムのパスの間を変換するファイル プラグインを使用する必要があります。 + + URL の文字列 CDVFilesystemURL * url から CDVFilesystem URL オブジェクトを取得 [CDVFilesystemURL fileSystemURLWithString:cdvfileURL]; + ファイル NSString * パスにマップできない場合は nil または URL オブジェクトのパスを取得 [filePlugin filesystemPathForURL:url]; + + + デバイス ・ パスの CDVFilesystem の URL オブジェクトを取得または//cdvfile URL として表現できない場合は nil です。 + CDVFilesystemURL の url = [filePlugin fileSystemURLforLocalPath:path]; + URL オブジェクト NSString * cdvfileURL の文字列表現を取得する = [url absoluteString]; + + +あなたのプラグインは、ファイルを作成しをファイル オブジェクトを返す場合、ファイルのプラグインを使用します。 + + デバイス ・ パスの CDVFilesystem の URL オブジェクトを取得または//cdvfile URL として表現できない場合は nil です。 + CDVFilesystemURL の url = [filePlugin fileSystemURLforLocalPath:path]; + JavaScript NSDictionary * エントリに戻る構造を得る = [filePlugin makeEntryForLocalURL:url] + + +#### Java スクリプトの設定 + +Java スクリプトの設定を取得するに、 `cdvfile://` ファイルまたは DirectoryEntry オブジェクトからの URL を呼び出して、 `.toURL()` それを。 + + var cdvfileURL = entry.toURL(); + + +プラグイン応答ハンドラーに返された FileEntry 構造体の実際のエントリ オブジェクトを変換する、ハンドラーのコード ファイルのプラグインをインポート、新しいオブジェクトを作成します。 + + 適切なエントリ オブジェクト var エントリを作成します。 + 場合 (entryStruct.isDirectory) {エントリ = 新しい DirectoryEntry (entryStruct.name、entryStruct.fullPath、新しい FileSystem(entryStruct.filesystemName));} 他 {エントリ = 新しいファイル (entryStruct.name、entryStruct.fullPath、新しい FileSystem(entryStruct.filesystemName));} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/ko/README.md b/mobile/plugins/cordova-plugin-file/doc/ko/README.md new file mode 100644 index 0000000..a3f3e94 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/ko/README.md @@ -0,0 +1,335 @@ + + +# cordova-plugin-file + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg)](https://travis-ci.org/apache/cordova-plugin-file) + +이 플러그인은 장치에 있는 파일에 대 한 읽기/쓰기 액세스를 허용 하는 파일 API를 구현 합니다. + +이 플러그인을 포함 한 몇 가지 사양에 따라: HTML5 파일 API는 + +(지금은 없어진) 디렉터리와 시스템 확장 최신: 플러그인 코드의 대부분은 때 이전 사양 작성 되었습니다 있지만 현재는: + +그것은 또한 FileWriter 사양 구현: + +사용을 참조 하십시오 HTML5 바위 ' 우수한 [파일 시스템 문서.](http://www.html5rocks.com/en/tutorials/file/filesystem/) + +다른 저장소 옵션에 대 한 개요, 코르도바의 [저장소 가이드](http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html) 를 참조합니다. + +이 플러그인 글로벌 `cordova.file` 개체를 정의합니다. + +전역 범위에 있지만 그것은 불가능까지 `deviceready` 이벤트 후. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## 설치 + + cordova plugin add cordova-plugin-file + + +## 지원 되는 플랫폼 + + * 아마존 화재 운영 체제 + * 안 드 로이드 + * 블랙베리 10 + * Firefox 운영 체제 + * iOS + * Windows Phone 7과 8 * + * 윈도우 8 * + * Windows* + * 브라우저 + +\* *These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`.* + +## 파일을 저장할 위치를 + +V1.2.0, 현재 중요 한 파일 시스템 디렉터리에 Url도 제공 됩니다. 각 URL 형태 *file:///path/to/spot/* 이며 `DirectoryEntry` `window.resolveLocalFileSystemURL()`를 사용 하 여 변환할 수 있습니다.. + + * `cordova.file.applicationDirectory`-읽기 전용 디렉터리는 응용 프로그램을 설치 합니다. (*iOS*, *안 드 로이드*, *블랙베리 10*) + + * `cordova.file.applicationStorageDirectory`응용 프로그램의 샌드박스;의 루트 디렉터리 iOS에이 위치에는 읽기 전용 (특정 하위 디렉토리만 [같은 `/Documents` ]은 읽기 / 쓰기). 포함 된 모든 데이터는 응용 프로그램에 전용. ( *iOS*, *안 드 로이드*, *블랙베리 10*) + + * `cordova.file.dataDirectory`-내부 메모리를 사용 하 여 응용 프로그램의 샌드박스 내에서 영구 및 개인 데이터 스토리지 (안 드 로이드, 외부 메모리를 사용 해야 하는 경우 사용 하 여 `.externalDataDirectory` ). IOS에이 디렉터리 iCloud와 동기화 되지 되 (를 사용 하 여 `.syncedDataDirectory` ). (*iOS*, *안 드 로이드*, *블랙베리 10*) + + * `cordova.file.cacheDirectory`-디렉터리 캐시 데이터 파일 또는 모든 파일을 당신의 app를 다시 쉽게 만들 수 있습니다. 운영 체제 장치 저장소 부족 하면 이러한 파일을 삭제할 수 있습니다, 그리고 그럼에도 불구 하 고, 애플 리 케이 션 여기에 파일을 삭제 하려면 운영 체제에 의존 하지 말아야 합니다. (*iOS*, *안 드 로이드*, *블랙베리 10*) + + * `cordova.file.externalApplicationStorageDirectory`-응용 프로그램 외부 저장 공간입니다. (*안 드 로이드*) + + * `cordova.file.externalDataDirectory`-외부 저장소에 응용 프로그램 특정 데이터 파일을 넣어 어디. (*안 드 로이드*) + + * `cordova.file.externalCacheDirectory`외부 저장소에 응용 프로그램 캐시입니다. (*안 드 로이드*) + + * `cordova.file.externalRootDirectory`-외부 저장 (SD 카드) 루트입니다. (*안 드 로이드*, *블랙베리 10*) + + * `cordova.file.tempDirectory`-운영 체제에서 지울 수 있습니다 임시 디렉터리 것입니다. 이 디렉터리;를 운영 체제에 의존 하지 마십시오 귀하의 응용 프로그램 항상 해당 하는 경우 파일을 제거 해야 합니다. (*iOS*) + + * `cordova.file.syncedDataDirectory`-(ICloud)를 예를 들어 동기화 해야 하는 응용 프로그램 관련 파일을 보유 하 고 있습니다. (*iOS*) + + * `cordova.file.documentsDirectory`-파일 애플 리 케이 션, 하지만 그 개인은 다른 응용 프로그램 (예: Office 파일)에 의미입니다. (*iOS*) + + * `cordova.file.sharedDirectory`-모든 응용 프로그램 (*블랙베리 10* 에 전세계적으로 사용 가능한 파일) + +## 파일 시스템 레이아웃 + +하지만 구현 세부 사항을 기술적으로 `cordova.file.*` 속성 실제 장치에 실제 경로에 매핑하는 방법을 아는 것이 매우 유용할 수 있습니다. + +### iOS 파일 시스템 레이아웃 + +| 장치 경로 | `cordova.file.*` | `iosExtraFileSystems` | r/w? | 영구? | OS 지웁니다 | 동기화 | 개인 | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:----:|:--------:|:-------------:|:---:|:--:| +| `/ var/모바일/응용 프로그램/< UUID > /` | applicationStorageDirectory | - | r | N/A | N/A | N/A | 예 | +|    `appname.app/` | applicationDirectory | 번들 | r | N/A | N/A | N/A | 예 | +|       `www/` | - | - | r | N/A | N/A | N/A | 예 | +|    `Documents/` | documentsDirectory | 문서 | r/w | 예 | 없음 | 예 | 예 | +|       `NoCloud/` | - | 문서 nosync | r/w | 예 | 없음 | 없음 | 예 | +|    `Library` | - | 라이브러리 | r/w | 예 | 없음 | 그래? | 예 | +|       `NoCloud/` | dataDirectory | 라이브러리 nosync | r/w | 예 | 없음 | 없음 | 예 | +|       `Cloud/` | syncedDataDirectory | - | r/w | 예 | 없음 | 예 | 예 | +|       `Caches/` | cacheDirectory | 캐시 | r/w | 예 * | Yes**\* | 없음 | 예 | +|    `tmp/` | tempDirectory | - | r/w | No** | Yes**\* | 없음 | 예 | + +\ * 파일 응용 프로그램 다시 시작 및 업그레이드, 유지 하지만 때마다 OS 욕망이 디렉터리를 지울 수 있습니다. 앱 삭제 될 수 있습니다 모든 콘텐츠를 다시 만들 수 있어야 합니다. + +** 파일 응용 프로그램 다시 시작에서 지속 될 수 있습니다 하지만이 동작에 의존 하지 마십시오. 파일 여러 업데이트를 보장 하지 않습니다. 때 해당 앱이이 디렉터리에서 파일을 제거 해야, 이러한 파일을 제거할 때 (또는 경우에도) 운영 체제 보증 하지 않습니다으로. + +**\ * OS 그것이 필요를 느낀다 언제 든 지이 디렉터리의 내용을 취소 수 있습니다 하지만 이것에 의존 하지 마십시오. 이 디렉터리를 응용 프로그램에 대 한 적절 한 선택을 취소 해야 합니다. + +### 안 드 로이드 파일 시스템 레이아웃 + +| 장치 경로 | `cordova.file.*` | `AndroidExtraFileSystems` | r/w? | 영구? | OS 지웁니다 | 개인 | +|:------------------------------------------------ |:----------------------------------- |:------------------------- |:----:|:---:|:--------:|:--:| +| `file:///android_asset/` | applicationDirectory | | r | N/A | N/A | 예 | +| `/data/데이터/< app id > /` | applicationStorageDirectory | - | r/w | N/A | N/A | 예 | +|    `cache` | cacheDirectory | 캐시 | r/w | 예 | 예\* | 예 | +|    `files` | dataDirectory | 파일 | r/w | 예 | 없음 | 예 | +|       `Documents` | | 문서 | r/w | 예 | 없음 | 예 | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | 예 | 없음 | 없음 | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | 예 | 없음 | 없음 | +|       `cache` | externalCacheDirectry | 외부 캐시 | r/w | 예 | 없음** | 없음 | +|       `files` | externalDataDirectory | 파일 외부 | r/w | 예 | 없음 | 없음 | + +\ * 운영 체제 정기적으로이 디렉터리 삭제 수 있지만이 동작에 의존 하지 마십시오. 이 응용 프로그램이 디렉터리의 내용을 취소 합니다. 사용자 수동으로 캐시 제거 해야,이 디렉터리의 내용은 제거 됩니다. + +** 운영 체제 자동으로;이 디렉터리를 삭제 하지 않습니다 내용을 직접 관리에 대 한 책임이 있습니다. 사용자 수동으로 캐시 제거 합니다, 디렉터리의 내용은 제거 됩니다. + +**참고**: 외부 저장소를 탑재할 수 없는 경우 `cordova.file.external*` 속성은 `null`. + +### 블랙베리 10 파일 시스템 레이아웃 + +| 장치 경로 | `cordova.file.*` | r/w? | 영구? | OS 지웁니다 | 개인 | +|:----------------------------------------------------------- |:--------------------------- |:----:|:---:|:-------:|:--:| +| `file:///accounts/1000/appdata/ < app id > /` | applicationStorageDirectory | r | N/A | N/A | 예 | +|    `app/native` | applicationDirectory | r | N/A | N/A | 예 | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | 없음 | 예 | 예 | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | 예 | 없음 | 예 | +| `file:///accounts/1000/removable/sdcard` | externalRemovableDirectory | r/w | 예 | 없음 | 없음 | +| `file:///accounts/1000/shared` | sharedDirectory | r/w | 예 | 없음 | 없음 | + +*참고*: 모든 경로 /accounts/1000-enterprise를 기준으로 응용 프로그램 경계를 작동 하도록 배포 될 때. + +## 안 드 로이드 단점 + +### 안 드 로이드 영구 저장 위치 + +안 드 로이드 장치에 영구 파일을 저장할 여러 유효한 위치가 있다. 다양 한 가능성의 광범위 한 토론에 대 한 [이 페이지](http://developer.android.com/guide/topics/data/data-storage.html)를 참조 하십시오. + +플러그인의 이전 버전을 시작할 때, 장치는 SD 카드 (또는 해당 스토리지 파티션) 탑재 했다 주장 하는 여부에 따라 임시 및 영구 파일의 위치를 선택 합니다. SD 카드 마운트, 또는 큰 내부 스토리지 파티션에 사용할 수 있었습니다 (같은 넥서스 장치에) 그 후에 영구 파일 공간의 루트에 저장 됩니다. 이 모든 코르 도우 바 애플 리 케이 션 카드에 모두 사용할 수 있는 파일을 볼 수 있는 의미 합니다. + +SD 카드는 사용할 수 있는 경우 이전 버전에서 데이터 저장 `/data/data/`는 서로 다른 애플 리 케이 션을 분리 하지만 여전히 원인 데이터를 사용자 간에 공유할 수 있습니다. + +그것은 지금 내부 파일 저장 위치 또는 응용 프로그램의 `config.xml` 파일에 기본 설정으로 이전 논리를 사용 하 여 파일을 저장할 것인지를 선택할 수 있습니다. 이렇게 하려면 `config.xml`에이 두 줄 중 하나를 추가: + + + + + + +이 줄이 없으면 파일 플러그인은 기본적으로 `Compatibility`을 사용 합니다. 기본 태그,이 이러한 값 중 하나가 아닌 경우에 응용 프로그램이 시작 되지 않습니다. + +이전 (사전 1.0)을 사용 하는 경우 응용 프로그램 사용자에 게 발송 되었다 이전,이 플러그인의 버전 영구 파일 시스템에 저장 된 파일은 그리고 `Compatibility` 환경 설정을 설정 해야 합니다. "내부"의 위치 전환 그들의 응용 프로그램을 업그레이드 기존 사용자의 그들의 장치에 따라 그들의 이전에 저장 된 파일에 액세스할 수 수 있다는 뜻입니다. + +경우 응용 프로그램은 새로운, 또는 이전 영구 파일 시스템에 파일을 저장, `Internal` 설정은 일반적으로 권장 됩니다. + +### /Android_asset에 대 한 느린 재귀 작업 + +자산 디렉터리를 나열 하는 것은 안 드 로이드에 정말 느리다입니다. 속도 높일 수 있습니다 하지만, 안 드 로이드 프로젝트의 루트에 `src/android/build-extras.gradle` 를 추가 하 여 최대 (cordova-android@4.0.0 필요 이상). + +## iOS 단점 + + * `cordova.file.applicationStorageDirectory`읽기 전용; 루트 디렉터리 내에서 파일을 저장 하려고에 실패 합니다. 다른 중 하나를 사용 하 여 `cordova.file.*` iOS에 대해 정의 된 속성 (만 `applicationDirectory` 와 `applicationStorageDirectory` 는 읽기 전용). + * `FileReader.readAsText(blob, encoding)` + * `encoding`매개 변수는 지원 되지 않습니다, 및 효과에 항상 u t F-8 인코딩을 합니다. + +### iOS 영구 저장소 위치 + +IOS 디바이스에 영구 파일을 저장할 두 개의 유효한 위치가 있다: 문서 디렉터리 및 라이브러리 디렉터리. 플러그인의 이전 버전은 오직 문서 디렉토리에 영구 파일을 저장. 이 부작용 보다는 아니었다 수시로 특히 많은 작은 파일을 처리 하는 응용 프로그램에 대 한 의도, iTunes에 표시 모든 응용 프로그램 파일을 만드는 디렉터리의 용도 내보내기에 대 한 완전 한 문서를 생산 했다. + +그것은 지금 문서 또는 응용 프로그램의 `config.xml` 파일에 기본 설정으로 라이브러리 디렉토리에 파일을 저장할 것인지를 선택할 수 있습니다. 이렇게 하려면 `config.xml`에이 두 줄 중 하나를 추가: + + + + + + +이 줄이 없으면 파일 플러그인은 기본적으로 `Compatibility`을 사용 합니다. 기본 태그,이 이러한 값 중 하나가 아닌 경우에 응용 프로그램이 시작 되지 않습니다. + +이전 (사전 1.0)을 사용 하는 경우 응용 프로그램 사용자에 게 발송 되었다 이전,이 플러그인의 버전 영구 파일 시스템에 저장 된 파일은 그리고 `Compatibility` 환경 설정을 설정 해야 합니다. `Library`에 위치를 스위칭 기존 사용자에 게 응용 프로그램을 업그레이 드의 그들의 이전에 저장 된 파일에 액세스할 수 것을 의미할 것입니다. + +경우 응용 프로그램은 새로운, 또는 이전 영구 파일 시스템에 파일을 저장, `Library` 설정은 일반적으로 권장 됩니다. + +## 파이어 폭스 OS 단점 + +파일 시스템 API Firefox 운영 체제에서 기본적으로 지원 하지 및 indexedDB 위에 심으로 구현 됩니다. + + * 비어 있지 않은 디렉터리를 제거할 때 실패 하지 않습니다. + * 디렉터리에 대 한 메타 데이터를 지원 하지 않습니다. + * 메서드 `copyTo` 및 `moveTo` 디렉터리를 지원 하지 않습니다 + +다음 데이터 경로 지원 됩니다: * `applicationDirectory`-`xhr`를 사용 하 여 로컬 파일을 응용 프로그램 패키지를 가져옵니다. * `dataDirectory`-영구 응용 프로그램 특정 데이터 파일에 대 한. * `cacheDirectory`-응용 프로그램 다시 시작 해야 하는 캐시 된 파일 (애플 리 케이 션은 여기에 파일을 삭제 하려면 운영 체제에 의존 하지 말아야). + +## 브라우저 만지면 + +### 일반적인 단점 및 설명 + + * 각 브라우저는 샌드박스 자체 파일 시스템을 사용합니다. IE와 파이어 폭스 기반으로 IndexedDB를 사용합니다. 모든 브라우저는 경로에서 디렉터리 구분 기호로 슬래시를 사용합니다. + * 디렉터리 항목을 연속적으로 만들 수 있다. 예를 들어 전화 `fs.root.getDirectory ('dir1/dir2 ', {create:true}, successCallback, errorCallback)` d i r 1 존재 하지 않은 경우 실패 합니다. + * 플러그인 응용 프로그램 처음 시작할 영구 저장소를 사용 하 여 사용자 권한을 요청 합니다. + * 플러그인 지원 `cdvfile://localhost` (로컬 리소스)만. 즉, 외부 리소스는 `cdvfile`를 통해 지원 되지 않습니다.. + * 플러그인 ["파일 시스템 API 8.3 명명 제한"을](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions) 수행 하지 않습니다.. + * Blob 및 파일 ' `close` 함수는 지원 되지 않습니다. + * `FileSaver` 및 `BlobBuilder`는이 플러그 접속식에 의해 지원 되지 않습니다 그리고 명세서를 필요가 없습니다. + * 플러그인 `requestAllFileSystems`를 지원 하지 않습니다. 이 함수는 또한 사양에 빠진. + * 사용 하는 경우 디렉터리에서 항목 제거 되지 것입니다 `create: true` 기존 디렉터리에 대 한 플래그. + * 생성자를 통해 생성 된 파일은 지원 되지 않습니다. Entry.file 메서드를 대신 사용 해야 합니다. + * 각 브라우저 blob URL 참조에 대 한 그것의 자신의 형태를 사용합니다. + * `readAsDataURL` 기능을 지원 하지만 크롬에서 mediatype 항목 이름 확장명에 따라 달라 집니다, 그리고 mediatype IE에는 항상 빈 (`텍스트 일반` 사양에 따라 동일), 파이어 폭스에서 mediatype은 항상 `응용 프로그램/8 진수 스트림`. 예를 들어, 콘텐츠는 `abcdefg` 다음 파이어 폭스 반환 `데이터: 응용 프로그램 / 8 진수 스트림; base64, YWJjZGVmZw = =`, 즉 반환 `데이터:; base64, YWJjZGVmZw = =`, 반환 크롬 `데이터: < 항목 이름의 확장에 따라 mediatype >; base64, YWJjZGVmZw = =`. + * `toInternalURL` 양식 `file:///persistent/path/to/entry` (파이어 폭스, 인터넷 익스플로러)에서 경로 반환합니다. 크롬 양식 `cdvfile://localhost/persistent/file`에 경로 반환합니다.. + +### 크롬 특수 + + * 크롬 파일 시스템 장치 준비 이벤트 후 즉시 준비 되지 않습니다. 문제를 해결 하려면 `filePluginIsReady` 이벤트를 구독할 수 있습니다. 예를 들어: + +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` + +`Window.isFilePluginReadyRaised` 함수를 사용 하 여 이벤트가 이미 발생 여부를 확인할 수 있습니다. -window.requestFileSystem 임시 및 영구 파일 시스템 할당량 크롬에 제한 되지 않습니다. -크롬에서 영구 저장소를 증가 하려면 `window.initPersistentFileSystem` 메서드를 호출 해야 합니다. 영구 저장소 할당량은 기본적으로 5 메가바이트입니다. -크롬 필요 `-허용-파일-액세스-에서-파일` `file:///` 프로토콜을 통해 지원 API 인수를 실행 합니다. -플래그를 사용 하면 `파일` 개체 하지 변경할 수 `{create:true}` 때 기존 `항목`. -행사 `cancelable` 속성이로 설정 된 크롬에서. 이 [사양](http://dev.w3.org/2009/dap/file-system/file-writer.html) 대조적 이다. -크롬에서 `toURL` 함수 반환 합니다 `파일 시스템:`-응용 프로그램 호스트에 따라 경로 앞에. 예를 들어, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -`toURL` 함수 결과 디렉터리 항목의 경우에 후행 슬래시를 포함 하지 않습니다. 크롬 하지만 제대로 붙여 슬래시 url이 포함 된 디렉터리 해결합니다. -`resolveLocalFileSystemURL` 메서드 인바운드 `url`을 `파일 시스템` 접두사가 필요 합니다. 예를 들어, `url` 매개 변수 `resolveLocalFileSystemURL`에 대 한 안 드 로이드에서 양식 `file:///persistent/somefile.txt` 반대로 양식 `filesystem:file:///persistent/somefile.txt`에 있어야 합니다. -사용 되지 않는 `toNativeURL` 함수는 지원 되지 않습니다 및 stub에는 없습니다. -`setMetadata` 함수는 규격에 명시 되지 않은 및 지원 되지 않습니다. -INVALID_MODIFICATION_ERR (코드: 9) 대신 throw 됩니다 SYNTAX_ERR(code: 8) 비 existant 파일 시스템의 요청에. -INVALID_MODIFICATION_ERR (코드: 9) 대신 throw 됩니다 PATH_EXISTS_ERR(code: 12) 독점적으로 파일 또는 디렉터리를 만들 려,는 이미 존재 합니다. -INVALID_MODIFICATION_ERR (코드: 9) 대신 throw 됩니다 NO_MODIFICATION_ALLOWED_ERR(code: 6) 루트 파일 시스템에 removeRecursively을 호출 하려고 합니다. -INVALID_MODIFICATION_ERR (코드: 9) 대신 throw 됩니다 NOT_FOUND_ERR(code: 1) moveTo 디렉터리 존재 하지 않는 것을 시도에. + +### IndexedDB 기반 구현이 특수 (파이어 폭스와 IE) + + * `.` `.`는 지원 되지 않습니다. + * IE `file:///`를 지원 하지 않습니다-모드; 호스트 모드 지원된 (http://localhost:xxxx)입니다. + * 파이어 폭스 파일 시스템 크기 제한 이지만 각 50MB 확장 사용자 권한을 요청 합니다. IE10 최대 10 mb 결합 AppCache 및 IndexedDB 묻는 사이트 당 250 mb의 최대 최대 증가 될 수 있도록 하려는 경우 해당 수준에 충돌 한 번 메시지를 표시 하지 않고 파일 시스템의 구현에 사용을 허용 한다. 그래서 `size` 매개 변수 `requestFileSystem` 함수에 대 한 파이어 폭스와 IE에서 파일 시스템 영향을 주지 않습니다. + * `readAsBinaryString` 함수 사양에 명시 되지 않은 IE에서 지원 되지 않으며 stub에는 없습니다. + * `file.type`은 항상 null입니다. + * 하지 항목 삭제 된 DirectoryEntry 인스턴스의 콜백 결과 사용 하 여 만들어야 합니다. 그렇지 않으면, '교수형 항목'을 얻을 것 이다. + * 그냥 작성 된 파일을 읽을 수 있는이 파일의 새 인스턴스를 얻으려면 해야 합니다. + * `setMetadata` 함수는 사양에 명시 되지 않은 지원 `modificationTime` 필드 변경에만 해당 합니다. + * `copyTo` 및 `moveTo` 함수는 디렉터리를 지원 하지 않습니다. + * 디렉터리 메타 데이터는 지원 되지 않습니다. + * 둘 다 Entry.remove와 directoryEntry.removeRecursively 비어 있지 않은 디렉터리를 제거할 때 실패 하지 않습니다-디렉터리 제거 되는 대신 내용을 함께 청소. + * `abort` 및 `truncate` 함수 지원 되지 않습니다. + * 진행 이벤트가 발생 하지 합니다. 예를 들어,이 처리기 하지 실행 됩니다. + +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## 업그레이드 노트 + +이 플러그인의 v1.0.0에 게시 된 사양에 맞춰 더 많은 것 `FileEntry` 및 `DirectoryEntry` 구조 변경 되었습니다. + +플러그인의 이전 (pre-1.0.0) 버전 장치 절대 파일 위치 `Entry` 개체의 `fullPath` 속성에 저장 됩니다. 이러한 경로 일반적으로 같습니다. + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +이러한 경로 `항목` 개체의 `toURL()` 메서드에서 반환 했다. + +V1.0.0, `fullPath` 속성은 *HTML 파일 시스템의 루트에 상대적인* 파일의 경로를. 그래서, 위의 경로 지금 둘 다의 `fullPath`와 `FileEntry` 개체에 의해 표현 될 것 이다 + + /path/to/file + + +응용 프로그램 작동 장치 절대 경로, 이전 `항목` 개체의 `fullPath` 속성을 통해 그 경로 검색 하는 경우에, 당신은 대신 `entry.toURL()`를 사용 하 여 코드를 업데이트 해야 합니다. + +대 한 뒤 호환성, `resolveLocalFileSystemURL()` 메서드는 장치-절대-경로 수락 하 고 그 파일 중 `TEMPORARY` 또는 `PERSISTENT` 파일 시스템 내에서 존재 하는 경우, 해당 `Entry` 개체를 반환 합니다. + +이 특히 이전 장치 절대 경로 사용 하는 파일 전송 플러그인에 문제가 있다 (그리고 아직도 그들을 받아들일 수.) 그것은 `entry.toURL()`와 `entry.fullPath`를 대체 확인 장치에 파일을 사용 하는 플러그인을 지 고 그래서 파일 시스템 Url와 함께 제대로 작동 하려면 업데이트 되었습니다. + +V1.1.0에 `toURL()`의 반환 값 (\[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394) 참조)로 바뀌었다 'file://' 절대 URL을 반환. 가능 하다 면. 보장 하는 ' cdvfile:'-URL `toInternalURL()`를 지금 사용할 수 있습니다. 이 메서드 이제 양식의 파일 Url을 반환 합니다. + + cdvfile://localhost/persistent/path/to/file + + +어떤 파일을 고유 하 게 식별 하려면 사용할 수 있습니다. + +## 오류 코드 및 의미의 목록 + +오류가 throw 됩니다 때 다음 코드 중 하나가 사용 됩니다. + +| 코드 | 상수 | +| --:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## (선택 사항) 플러그인 구성 + +사용 가능한 파일 시스템의 집합 플랫폼 당 구성된 될 수 있습니다. IOS와 안 드 로이드를 인식 한 `config.xml` 설치 될 파일 시스템 이름에 태그. 기본적으로 모든 파일 시스템 루트 사용할 수 있습니다. + + + + + +### 안 드 로이드 + + * `files`: 응용 프로그램의 내부 파일 저장 디렉토리 + * `files-external`: 응용 프로그램의 외부 파일 저장 디렉토리 + * `sdcard`: 글로벌 외부 파일 저장 디렉토리 (이것은 SD 카드의 루트 설치 된 경우). 이것을 사용 하려면 `android.permission.WRITE_EXTERNAL_STORAGE` 권한이 있어야 합니다. + * `cache`: 응용 프로그램의 내부 캐시 디렉터리 + * `cache-external`: 응용 프로그램의 외부 캐시 디렉터리 + * `root`: 전체 장치 파일 시스템 + +안 드 로이드는 또한 "파일" 파일 시스템 내에서 "/ 문서 /" 하위 디렉토리를 나타내는 "문서" 라는 특별 한 파일을 지원 합니다. + +### iOS + + * `library`: 응용 프로그램의 라이브러리 디렉터리 + * `documents`: 응용 프로그램의 문서 디렉토리 + * `cache`: 응용 프로그램의 캐시 디렉터리 + * `bundle`: 응용 프로그램의 번들; (읽기 전용) 디스크에 응용 프로그램 자체의 위치 + * `root`: 전체 장치 파일 시스템 + +기본적으로 라이브러리 및 문서 디렉토리 iCloud에 동기화 할 수 있습니다. 또한 2 개의 추가적인 파일 시스템, `library-nosync` 및 `documents-nosync`, 내 특별 한 동기화 되지 않은 디렉터리를 대표 하는 요청할 수 있습니다는 `/Library` 또는 `/Documents` 파일 시스템. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/ko/index.md b/mobile/plugins/cordova-plugin-file/doc/ko/index.md new file mode 100644 index 0000000..08340d8 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/ko/index.md @@ -0,0 +1,338 @@ + + +# cordova-plugin-file + +이 플러그인은 장치에 있는 파일에 대 한 읽기/쓰기 액세스를 허용 하는 파일 API를 구현 합니다. + +이 플러그인을 포함 한 몇 가지 사양에 따라: HTML5 파일 API는 + +(지금은 없어진) 디렉터리와 시스템 확장 최신: 플러그인 코드의 대부분은 때 이전 사양 작성 되었습니다 있지만 현재는: + +그것은 또한 FileWriter 사양 구현: + +사용을 참조 하십시오 HTML5 바위 ' 우수한 [파일 시스템 문서.][1] + + [1]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +다른 저장소 옵션에 대 한 개요, 코르도바의 [저장소 가이드][2] 를 참조합니다. + + [2]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +이 플러그인 글로벌 `cordova.file` 개체를 정의합니다. + +전역 범위에 있지만 그것은 불가능까지 `deviceready` 이벤트 후. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## 설치 + + cordova plugin add cordova-plugin-file + + +## 지원 되는 플랫폼 + +* 아마존 화재 운영 체제 +* 안 드 로이드 +* 블랙베리 10 +* Firefox 운영 체제 +* iOS +* Windows Phone 7과 8 * +* 윈도우 8 * +* 브라우저 + +* *`FileReader.readAsArrayBuffer`도 `FileWriter.write(blob)`이 플랫폼을 지원 하지 않습니다.* + +## 파일을 저장할 위치를 + +V1.2.0, 현재 중요 한 파일 시스템 디렉터리에 Url도 제공 됩니다. 각 URL 형태 *file:///path/to/spot/* 이며 `DirectoryEntry` `window.resolveLocalFileSystemURL()`를 사용 하 여 변환할 수 있습니다.. + +* `cordova.file.applicationDirectory`-읽기 전용 디렉터리는 응용 프로그램을 설치 합니다. (*iOS*, *안 드 로이드*, *블랙베리 10*) + +* `cordova.file.applicationStorageDirectory`응용 프로그램의 샌드박스;의 루트 디렉터리 iOS에이 위치에는 읽기 전용 (특정 하위 디렉토리만 [같은 `/Documents` ]은 읽기 / 쓰기). 포함 된 모든 데이터는 응용 프로그램에 전용. ( *iOS*, *안 드 로이드*, *블랙베리 10*) + +* `cordova.file.dataDirectory`-내부 메모리를 사용 하 여 응용 프로그램의 샌드박스 내에서 영구 및 개인 데이터 스토리지 (안 드 로이드, 외부 메모리를 사용 해야 하는 경우 사용 하 여 `.externalDataDirectory` ). IOS에이 디렉터리 iCloud와 동기화 되지 되 (를 사용 하 여 `.syncedDataDirectory` ). (*iOS*, *안 드 로이드*, *블랙베리 10*) + +* `cordova.file.cacheDirectory`-디렉터리 캐시 데이터 파일 또는 모든 파일을 당신의 app를 다시 쉽게 만들 수 있습니다. 운영 체제 장치 저장소 부족 하면 이러한 파일을 삭제할 수 있습니다, 그리고 그럼에도 불구 하 고, 애플 리 케이 션 여기에 파일을 삭제 하려면 운영 체제에 의존 하지 말아야 합니다. (*iOS*, *안 드 로이드*, *블랙베리 10*) + +* `cordova.file.externalApplicationStorageDirectory`-응용 프로그램 외부 저장 공간입니다. (*안 드 로이드*) + +* `cordova.file.externalDataDirectory`-외부 저장소에 응용 프로그램 특정 데이터 파일을 넣어 어디. (*안 드 로이드*) + +* `cordova.file.externalCacheDirectory`외부 저장소에 응용 프로그램 캐시입니다. (*안 드 로이드*) + +* `cordova.file.externalRootDirectory`-외부 저장 (SD 카드) 루트입니다. (*안 드 로이드*, *블랙베리 10*) + +* `cordova.file.tempDirectory`-운영 체제에서 지울 수 있습니다 임시 디렉터리 것입니다. 이 디렉터리;를 운영 체제에 의존 하지 마십시오 귀하의 응용 프로그램 항상 해당 하는 경우 파일을 제거 해야 합니다. (*iOS*) + +* `cordova.file.syncedDataDirectory`-(ICloud)를 예를 들어 동기화 해야 하는 응용 프로그램 관련 파일을 보유 하 고 있습니다. (*iOS*) + +* `cordova.file.documentsDirectory`-파일 애플 리 케이 션, 하지만 그 개인은 다른 응용 프로그램 (예: Office 파일)에 의미입니다. (*iOS*) + +* `cordova.file.sharedDirectory`-모든 응용 프로그램 (*블랙베리 10* 에 전세계적으로 사용 가능한 파일) + +## 파일 시스템 레이아웃 + +하지만 구현 세부 사항을 기술적으로 `cordova.file.*` 속성 실제 장치에 실제 경로에 매핑하는 방법을 아는 것이 매우 유용할 수 있습니다. + +### iOS 파일 시스템 레이아웃 + +| 장치 경로 | `cordova.file.*` | `iosExtraFileSystems` | r/w? | 영구? | OS 지웁니다 | 동기화 | 개인 | +|:------------------------------------ |:--------------------------- |:--------------------- |:----:|:------:|:---------:|:---:|:--:| +| `/ var/모바일/응용 프로그램/< UUID > /` | applicationStorageDirectory | - | r | N/A | N/A | N/A | 예 | +|    `appname.app/` | applicationDirectory | 번들 | r | N/A | N/A | N/A | 예 | +|       `www/` | - | - | r | N/A | N/A | N/A | 예 | +|    `Documents/` | documentsDirectory | 문서 | r/w | 예 | 없음 | 예 | 예 | +|       `NoCloud/` | - | 문서 nosync | r/w | 예 | 없음 | 없음 | 예 | +|    `Library` | - | 라이브러리 | r/w | 예 | 없음 | 그래? | 예 | +|       `NoCloud/` | dataDirectory | 라이브러리 nosync | r/w | 예 | 없음 | 없음 | 예 | +|       `Cloud/` | syncedDataDirectory | - | r/w | 예 | 없음 | 예 | 예 | +|       `Caches/` | cacheDirectory | 캐시 | r/w | 예 * | 예 * * *| | 없음 | 예 | +|    `tmp/` | tempDirectory | - | r/w | 아니 * * | 예 * * *| | 없음 | 예 | + +* 파일 응용 프로그램 다시 시작 및 업그레이드, 유지 하지만 OS 욕망 언제 든 지이 디렉터리를 지울 수 있습니다. 앱 삭제 될 수 있습니다 모든 콘텐츠를 다시 만들 수 있어야 합니다. + +* * 파일 응용 프로그램 다시 시작에서 지속 될 수 있습니다 하지만이 동작에 의존 하지 마십시오. 파일 여러 업데이트를 보장 하지 않습니다. 때 해당 앱이이 디렉터리에서 파일을 제거 해야, 이러한 파일을 제거할 때 (또는 경우에도) 운영 체제 보증 하지 않습니다으로. + +* * *| OS 그것이 필요를 느낀다 언제 든 지이 디렉터리의 내용을 취소 될 수 있습니다 하지만 이것에 의존 하지 마십시오. 이 디렉터리를 응용 프로그램에 대 한 적절 한 선택을 취소 해야 합니다. + +### 안 드 로이드 파일 시스템 레이아웃 + +| 장치 경로 | `cordova.file.*` | `AndroidExtraFileSystems` | r/w? | 영구? | OS 지웁니다 | 개인 | +|:--------------------------------- |:----------------------------------- |:------------------------- |:----:|:---:|:-------:|:--:| +| `file:///android_asset/` | applicationDirectory | | r | N/A | N/A | 예 | +| `/data/데이터/< app id > /` | applicationStorageDirectory | - | r/w | N/A | N/A | 예 | +|    `cache` | cacheDirectory | 캐시 | r/w | 예 | 예 * | 예 | +|    `files` | dataDirectory | 파일 | r/w | 예 | 없음 | 예 | +|       `Documents` | | 문서 | r/w | 예 | 없음 | 예 | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | 예 | 없음 | 없음 | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | 예 | 없음 | 없음 | +|       `cache` | externalCacheDirectry | 외부 캐시 | r/w | 예 | 아니 * * | 없음 | +|       `files` | externalDataDirectory | 파일 외부 | r/w | 예 | 없음 | 없음 | + +* OS 수 있습니다 정기적으로이 디렉터리에 있지만이 동작에 의존 하지 마십시오. 이 응용 프로그램이 디렉터리의 내용을 취소 합니다. 사용자 수동으로 캐시 제거 해야,이 디렉터리의 내용은 제거 됩니다. + +* * OS 지워지지 않습니다이 디렉터리 자동으로; 콘텐츠를 관리 하기 위한 책임이 있습니다. 사용자 수동으로 캐시 제거 합니다, 디렉터리의 내용은 제거 됩니다. + +**참고**: 외부 저장소를 탑재할 수 없는 경우 `cordova.file.external*` 속성은 `null`. + +### 블랙베리 10 파일 시스템 레이아웃 + +| 장치 경로 | `cordova.file.*` | r/w? | 영구? | OS 지웁니다 | 개인 | +|:--------------------------------------------------- |:--------------------------- |:----:|:---:|:-------:|:--:| +| `file:///accounts/1000/appdata/ < app id > /` | applicationStorageDirectory | r | N/A | N/A | 예 | +|    `app/native` | applicationDirectory | r | N/A | N/A | 예 | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | 없음 | 예 | 예 | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | 예 | 없음 | 예 | +| `file:///accounts/1000/removable/sdcard` | externalRemovableDirectory | r/w | 예 | 없음 | 없음 | +| `file:///accounts/1000/shared` | sharedDirectory | r/w | 예 | 없음 | 없음 | + +*참고*: 모든 경로 /accounts/1000-enterprise를 기준으로 응용 프로그램 경계를 작동 하도록 배포 될 때. + +## 안 드 로이드 단점 + +### 안 드 로이드 영구 저장 위치 + +안 드 로이드 장치에 영구 파일을 저장할 여러 유효한 위치가 있다. 다양 한 가능성의 광범위 한 토론에 대 한 [이 페이지][3]를 참조 하십시오. + + [3]: http://developer.android.com/guide/topics/data/data-storage.html + +플러그인의 이전 버전을 시작할 때, 장치는 SD 카드 (또는 해당 스토리지 파티션) 탑재 했다 주장 하는 여부에 따라 임시 및 영구 파일의 위치를 선택 합니다. SD 카드 마운트, 또는 큰 내부 스토리지 파티션에 사용할 수 있었습니다 (같은 넥서스 장치에) 그 후에 영구 파일 공간의 루트에 저장 됩니다. 이 모든 코르 도우 바 애플 리 케이 션 카드에 모두 사용할 수 있는 파일을 볼 수 있는 의미 합니다. + +SD 카드는 사용할 수 있는 경우 이전 버전에서 데이터 저장 `/data/data/`는 서로 다른 애플 리 케이 션을 분리 하지만 여전히 원인 데이터를 사용자 간에 공유할 수 있습니다. + +그것은 지금 내부 파일 저장 위치 또는 응용 프로그램의 `config.xml` 파일에 기본 설정으로 이전 논리를 사용 하 여 파일을 저장할 것인지를 선택할 수 있습니다. 이렇게 하려면 `config.xml`에이 두 줄 중 하나를 추가: + + + + + + +이 줄이 없으면 파일 플러그인은 기본적으로 `Compatibility`을 사용 합니다. 기본 태그,이 이러한 값 중 하나가 아닌 경우에 응용 프로그램이 시작 되지 않습니다. + +이전 (사전 1.0)을 사용 하는 경우 응용 프로그램 사용자에 게 발송 되었다 이전,이 플러그인의 버전 영구 파일 시스템에 저장 된 파일은 그리고 `Compatibility` 환경 설정을 설정 해야 합니다. "내부"의 위치 전환 그들의 응용 프로그램을 업그레이드 기존 사용자의 그들의 장치에 따라 그들의 이전에 저장 된 파일에 액세스할 수 수 있다는 뜻입니다. + +경우 응용 프로그램은 새로운, 또는 이전 영구 파일 시스템에 파일을 저장, `Internal` 설정은 일반적으로 권장 됩니다. + +## iOS 단점 + +* `cordova.file.applicationStorageDirectory`읽기 전용; 루트 디렉터리 내에서 파일을 저장 하려고에 실패 합니다. 다른 중 하나를 사용 하 여 `cordova.file.*` iOS에 대해 정의 된 속성 (만 `applicationDirectory` 와 `applicationStorageDirectory` 는 읽기 전용). +* `FileReader.readAsText(blob, encoding)` + * `encoding`매개 변수는 지원 되지 않습니다, 및 효과에 항상 u t F-8 인코딩을 합니다. + +### iOS 영구 저장소 위치 + +IOS 디바이스에 영구 파일을 저장할 두 개의 유효한 위치가 있다: 문서 디렉터리 및 라이브러리 디렉터리. 플러그인의 이전 버전은 오직 문서 디렉토리에 영구 파일을 저장. 이 부작용 보다는 아니었다 수시로 특히 많은 작은 파일을 처리 하는 응용 프로그램에 대 한 의도, iTunes에 표시 모든 응용 프로그램 파일을 만드는 디렉터리의 용도 내보내기에 대 한 완전 한 문서를 생산 했다. + +그것은 지금 문서 또는 응용 프로그램의 `config.xml` 파일에 기본 설정으로 라이브러리 디렉토리에 파일을 저장할 것인지를 선택할 수 있습니다. 이렇게 하려면 `config.xml`에이 두 줄 중 하나를 추가: + + + + + + +이 줄이 없으면 파일 플러그인은 기본적으로 `Compatibility`을 사용 합니다. 기본 태그,이 이러한 값 중 하나가 아닌 경우에 응용 프로그램이 시작 되지 않습니다. + +이전 (사전 1.0)을 사용 하는 경우 응용 프로그램 사용자에 게 발송 되었다 이전,이 플러그인의 버전 영구 파일 시스템에 저장 된 파일은 그리고 `Compatibility` 환경 설정을 설정 해야 합니다. `Library`에 위치를 스위칭 기존 사용자에 게 응용 프로그램을 업그레이 드의 그들의 이전에 저장 된 파일에 액세스할 수 것을 의미할 것입니다. + +경우 응용 프로그램은 새로운, 또는 이전 영구 파일 시스템에 파일을 저장, `Library` 설정은 일반적으로 권장 됩니다. + +## 파이어 폭스 OS 단점 + +파일 시스템 API Firefox 운영 체제에서 기본적으로 지원 하지 및 indexedDB 위에 심으로 구현 됩니다. + +* 비어 있지 않은 디렉터리를 제거할 때 실패 하지 않습니다. +* 디렉터리에 대 한 메타 데이터를 지원 하지 않습니다. +* 메서드 `copyTo` 및 `moveTo` 디렉터리를 지원 하지 않습니다 + +다음 데이터 경로 지원 됩니다: * `applicationDirectory`-`xhr`를 사용 하 여 로컬 파일을 응용 프로그램 패키지를 가져옵니다. * `dataDirectory`-영구 응용 프로그램 특정 데이터 파일에 대 한. * `cacheDirectory`-응용 프로그램 다시 시작 해야 하는 캐시 된 파일 (애플 리 케이 션은 여기에 파일을 삭제 하려면 운영 체제에 의존 하지 말아야). + +## 브라우저 만지면 + +### 일반적인 단점 및 설명 + +* 각 브라우저는 샌드박스 자체 파일 시스템을 사용합니다. IE와 파이어 폭스 기반으로 IndexedDB를 사용합니다. 모든 브라우저는 경로에서 디렉터리 구분 기호로 슬래시를 사용합니다. +* 디렉터리 항목을 연속적으로 만들 수 있다. 예를 들어 전화 `fs.root.getDirectory ('dir1/dir2 ', {create:true}, successCallback, errorCallback)` d i r 1 존재 하지 않은 경우 실패 합니다. +* 플러그인 응용 프로그램 처음 시작할 영구 저장소를 사용 하 여 사용자 권한을 요청 합니다. +* 플러그인 지원 `cdvfile://localhost` (로컬 리소스)만. 즉, 외부 리소스는 `cdvfile`를 통해 지원 되지 않습니다.. +* 플러그인 ["파일 시스템 API 8.3 명명 제한"을][4] 수행 하지 않습니다.. +* Blob 및 파일 ' `close` 함수는 지원 되지 않습니다. +* `FileSaver` 및 `BlobBuilder`는이 플러그 접속식에 의해 지원 되지 않습니다 그리고 명세서를 필요가 없습니다. +* 플러그인 `requestAllFileSystems`를 지원 하지 않습니다. 이 함수는 또한 사양에 빠진. +* 사용 하는 경우 디렉터리에서 항목 제거 되지 것입니다 `create: true` 기존 디렉터리에 대 한 플래그. +* 생성자를 통해 생성 된 파일은 지원 되지 않습니다. Entry.file 메서드를 대신 사용 해야 합니다. +* 각 브라우저 blob URL 참조에 대 한 그것의 자신의 형태를 사용합니다. +* `readAsDataURL` 기능을 지원 하지만 크롬에서 mediatype 항목 이름 확장명에 따라 달라 집니다, 그리고 mediatype IE에는 항상 빈 (`텍스트 일반` 사양에 따라 동일), 파이어 폭스에서 mediatype은 항상 `응용 프로그램/8 진수 스트림`. 예를 들어, 콘텐츠는 `abcdefg` 다음 파이어 폭스 반환 `데이터: 응용 프로그램 / 8 진수 스트림; base64, YWJjZGVmZw = =`, 즉 반환 `데이터:; base64, YWJjZGVmZw = =`, 반환 크롬 `데이터: < 항목 이름의 확장에 따라 mediatype >; base64, YWJjZGVmZw = =`. +* `toInternalURL` 양식 `file:///persistent/path/to/entry` (파이어 폭스, 인터넷 익스플로러)에서 경로 반환합니다. 크롬 양식 `cdvfile://localhost/persistent/file`에 경로 반환합니다.. + + [4]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions + +### 크롬 특수 + +* 크롬 파일 시스템 장치 준비 이벤트 후 즉시 준비 되지 않습니다. 문제를 해결 하려면 `filePluginIsReady` 이벤트를 구독할 수 있습니다. 예를 들어: + + javascript + window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); + + +`Window.isFilePluginReadyRaised` 함수를 사용 하 여 이벤트가 이미 발생 여부를 확인할 수 있습니다. -window.requestFileSystem 임시 및 영구 파일 시스템 할당량 크롬에 제한 되지 않습니다. -크롬에서 영구 저장소를 증가 하려면 `window.initPersistentFileSystem` 메서드를 호출 해야 합니다. 영구 저장소 할당량은 기본적으로 5 메가바이트입니다. -크롬 필요 `-허용-파일-액세스-에서-파일` `file:///` 프로토콜을 통해 지원 API 인수를 실행 합니다. -플래그를 사용 하면 `파일` 개체 하지 변경할 수 `{create:true}` 때 기존 `항목`. -행사 `cancelable` 속성이로 설정 된 크롬에서. 이 [사양][5] 대조적 이다. -크롬에서 `toURL` 함수 반환 합니다 `파일 시스템:`-응용 프로그램 호스트에 따라 경로 앞에. 예를 들어, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -`toURL` 함수 결과 디렉터리 항목의 경우에 후행 슬래시를 포함 하지 않습니다. 크롬 하지만 제대로 붙여 슬래시 url이 포함 된 디렉터리 해결합니다. -`resolveLocalFileSystemURL` 메서드 인바운드 `url`을 `파일 시스템` 접두사가 필요 합니다. 예를 들어, `url` 매개 변수 `resolveLocalFileSystemURL`에 대 한 안 드 로이드에서 양식 `file:///persistent/somefile.txt` 반대로 양식 `filesystem:file:///persistent/somefile.txt`에 있어야 합니다. -사용 되지 않는 `toNativeURL` 함수는 지원 되지 않습니다 및 stub에는 없습니다. -`setMetadata` 함수는 규격에 명시 되지 않은 및 지원 되지 않습니다. -INVALID_MODIFICATION_ERR (코드: 9) 대신 throw 됩니다 SYNTAX_ERR(code: 8) 비 existant 파일 시스템의 요청에. -INVALID_MODIFICATION_ERR (코드: 9) 대신 throw 됩니다 PATH_EXISTS_ERR(code: 12) 독점적으로 파일 또는 디렉터리를 만들 려,는 이미 존재 합니다. -INVALID_MODIFICATION_ERR (코드: 9) 대신 throw 됩니다 NO_MODIFICATION_ALLOWED_ERR(code: 6) 루트 파일 시스템에 removeRecursively을 호출 하려고 합니다. -INVALID_MODIFICATION_ERR (코드: 9) 대신 throw 됩니다 NOT_FOUND_ERR(code: 1) moveTo 디렉터리 존재 하지 않는 것을 시도에. + + [5]: http://dev.w3.org/2009/dap/file-system/file-writer.html + +### IndexedDB 기반 구현이 특수 (파이어 폭스와 IE) + +* `.` `.`는 지원 되지 않습니다. +* IE `file:///`를 지원 하지 않습니다-모드; 호스트 모드 지원된 (http://localhost:xxxx)입니다. +* 파이어 폭스 파일 시스템 크기 제한 이지만 각 50MB 확장 사용자 권한을 요청 합니다. IE10 최대 10 mb 결합 AppCache 및 IndexedDB 묻는 사이트 당 250 mb의 최대 최대 증가 될 수 있도록 하려는 경우 해당 수준에 충돌 한 번 메시지를 표시 하지 않고 파일 시스템의 구현에 사용을 허용 한다. 그래서 `size` 매개 변수 `requestFileSystem` 함수에 대 한 파이어 폭스와 IE에서 파일 시스템 영향을 주지 않습니다. +* `readAsBinaryString` 함수 사양에 명시 되지 않은 IE에서 지원 되지 않으며 stub에는 없습니다. +* `file.type`은 항상 null입니다. +* 하지 항목 삭제 된 DirectoryEntry 인스턴스의 콜백 결과 사용 하 여 만들어야 합니다. 그렇지 않으면, '교수형 항목'을 얻을 것 이다. +* 그냥 작성 된 파일을 읽을 수 있는이 파일의 새 인스턴스를 얻으려면 해야 합니다. +* `setMetadata` 함수는 사양에 명시 되지 않은 지원 `modificationTime` 필드 변경에만 해당 합니다. +* `copyTo` 및 `moveTo` 함수는 디렉터리를 지원 하지 않습니다. +* 디렉터리 메타 데이터는 지원 되지 않습니다. +* 둘 다 Entry.remove와 directoryEntry.removeRecursively 비어 있지 않은 디렉터리를 제거할 때 실패 하지 않습니다-디렉터리 제거 되는 대신 내용을 함께 청소. +* `abort` 및 `truncate` 함수 지원 되지 않습니다. +* 진행 이벤트가 발생 하지 합니다. 예를 들어,이 처리기 하지 실행 됩니다. + + javascript + writer.onprogress = function() { /*commands*/ }; + + +## 업그레이드 노트 + +이 플러그인의 v1.0.0에 게시 된 사양에 맞춰 더 많은 것 `FileEntry` 및 `DirectoryEntry` 구조 변경 되었습니다. + +플러그인의 이전 (pre-1.0.0) 버전 장치 절대 파일 위치 `Entry` 개체의 `fullPath` 속성에 저장 됩니다. 이러한 경로 일반적으로 같습니다. + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +이러한 경로 `항목` 개체의 `toURL()` 메서드에서 반환 했다. + +V1.0.0, `fullPath` 속성은 *HTML 파일 시스템의 루트에 상대적인* 파일의 경로를. 그래서, 위의 경로 지금 둘 다의 `fullPath`와 `FileEntry` 개체에 의해 표현 될 것 이다 + + /path/to/file + + +응용 프로그램 작동 장치 절대 경로, 이전 `항목` 개체의 `fullPath` 속성을 통해 그 경로 검색 하는 경우에, 당신은 대신 `entry.toURL()`를 사용 하 여 코드를 업데이트 해야 합니다. + +대 한 뒤 호환성, `resolveLocalFileSystemURL()` 메서드는 장치-절대-경로 수락 하 고 그 파일 중 `TEMPORARY` 또는 `PERSISTENT` 파일 시스템 내에서 존재 하는 경우, 해당 `Entry` 개체를 반환 합니다. + +이 특히 이전 장치 절대 경로 사용 하는 파일 전송 플러그인에 문제가 있다 (그리고 아직도 그들을 받아들일 수.) 그것은 `entry.toURL()`와 `entry.fullPath`를 대체 확인 장치에 파일을 사용 하는 플러그인을 지 고 그래서 파일 시스템 Url와 함께 제대로 작동 하려면 업데이트 되었습니다. + +V1.1.0에 `toURL()`의 반환 값 (\[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394) 참조)로 바뀌었다 'file://' 절대 URL을 반환. 가능 하다 면. 보장 하는 ' cdvfile:'-URL `toInternalURL()`를 지금 사용할 수 있습니다. 이 메서드 이제 양식의 파일 Url을 반환 합니다. + + cdvfile://localhost/persistent/path/to/file + + +어떤 파일을 고유 하 게 식별 하려면 사용할 수 있습니다. + +## 오류 코드 및 의미의 목록 + +오류가 throw 됩니다 때 다음 코드 중 하나가 사용 됩니다. + +| 코드 | 상수 | +| --:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## (선택 사항) 플러그인 구성 + +사용 가능한 파일 시스템의 집합 플랫폼 당 구성된 될 수 있습니다. IOS와 안 드 로이드를 인식 한 `config.xml` 설치 될 파일 시스템 이름에 태그. 기본적으로 모든 파일 시스템 루트 사용할 수 있습니다. + + + + + +### 안 드 로이드 + +* `files`: 응용 프로그램의 내부 파일 저장 디렉토리 +* `files-external`: 응용 프로그램의 외부 파일 저장 디렉토리 +* `sdcard`: 글로벌 외부 파일 저장 디렉토리 (이것은 SD 카드의 루트 설치 된 경우). 이것을 사용 하려면 `android.permission.WRITE_EXTERNAL_STORAGE` 권한이 있어야 합니다. +* `cache`: 응용 프로그램의 내부 캐시 디렉터리 +* `cache-external`: 응용 프로그램의 외부 캐시 디렉터리 +* `root`: 전체 장치 파일 시스템 + +안 드 로이드는 또한 "파일" 파일 시스템 내에서 "/ 문서 /" 하위 디렉토리를 나타내는 "문서" 라는 특별 한 파일을 지원 합니다. + +### iOS + +* `library`: 응용 프로그램의 라이브러리 디렉터리 +* `documents`: 응용 프로그램의 문서 디렉토리 +* `cache`: 응용 프로그램의 캐시 디렉터리 +* `bundle`: 응용 프로그램의 번들; (읽기 전용) 디스크에 응용 프로그램 자체의 위치 +* `root`: 전체 장치 파일 시스템 + +기본적으로 라이브러리 및 문서 디렉토리 iCloud에 동기화 할 수 있습니다. 또한 2 개의 추가적인 파일 시스템, `library-nosync` 및 `documents-nosync`, 내 특별 한 동기화 되지 않은 디렉터리를 대표 하는 요청할 수 있습니다는 `/Library` 또는 `/Documents` 파일 시스템. diff --git a/mobile/plugins/cordova-plugin-file/doc/ko/plugins.md b/mobile/plugins/cordova-plugin-file/doc/ko/plugins.md new file mode 100644 index 0000000..31b274d --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/ko/plugins.md @@ -0,0 +1,101 @@ + + +# 플러그인 개발자를 위한 노트 + +이 노트는 주로 파일 플러그인을 사용 하 여 파일 시스템 플러그인 인터페이스를 작성 하 고 싶은 안 드 로이드와 iOS 개발자를 위한 것입니다. + +## 코르 도우 바 파일 시스템 Url 사용 + +버전 1.0.0, 이후이 플러그인과 Url 사용 하고있다는 `cdvfile` 교량, 모든 통신에 대 한 제도 보다는 자바 원시 장치 파일 시스템 경로 노출. + +자바 스크립트 측면에서 즉 그 FileEntry 및 DirectoryEntry 개체 fullPath 속성을 HTML 파일 시스템의 루트에 상대적입니다. FileEntry 또는 DirectoryEntry 개체를 수락 하는 플러그인의 자바 API를 호출 해야 `.toURL()` 다리에 걸쳐 네이티브 코드에 전달 하기 전에 해당 개체에. + +### Cdvfile 변환: / / fileystem 경로 Url + +플러그인 파일 시스템을 작성 하는 실제 파일 시스템 위치에 받은 파일 시스템 URL을 변환 할 수 있습니다. 이렇게, 네이티브 플랫폼에 따라 여러 방법이 있다. + +기억 하는 것이 중요 하다 모든 `cdvfile://` Url은 실제 파일 장치에 매핑. 일부 Url 파일에 의해 표현 되지 않는 또는 심지어 원격 리소스를 참조할 수 있는 장치에 자산을 참조할 수 있습니다. 이러한 가능성 때문에 플러그인 경로를 Url을 변환 하려고 할 때 다시 의미 있는 결과 얻을 지 여부를 항상 테스트 해야 합니다. + +#### 안 드 로이드 + +안 드 로이드, 변환 하는 간단한 방법에는 `cdvfile://` URL을 파일 시스템 경로 사용 하는 `org.apache.cordova.CordovaResourceApi` . `CordovaResourceApi`처리할 수 있는 여러 가지 방법에는 `cdvfile://` Url: + + webView 플러그인 클래스 CordovaResourceApi resourceApi의 멤버인 = webView.getResourceApi(); + + 장치에이 파일을 나타내는 file:/// URL 얻기 / / 같은 URL 변경 파일 Uri fileURL에 매핑할 수 없는 경우 또는 = resourceApi.remapUri(Uri.parse(cdvfileURL)); + + +그것은 또한 파일 플러그인을 직접 사용할 수 있습니다: + + 가져오기 org.apache.cordova.file.FileUtils; + 가져오기 org.apache.cordova.file.FileSystem; + 가져오기 java.net.MalformedURLException; + + 플러그인 관리자에서 파일 플러그인을 얻을 FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + 그것 시도 대 한 경로 얻을 URL을 감안할 때, {문자열 경로 = filePlugin.filesystemPathForURL(cdvfileURL);} catch (MalformedURLException e) {/ / 파일 시스템 url 인식 되지 않았습니다} + + +경로를 변환 하는 `cdvfile://` URL: + + 가져오기 org.apache.cordova.file.LocalFilesystemURL; + + 장치 경로 대 한 LocalFilesystemURL 개체를 가져오기 / / cdvfile URL로 나타낼 수 없는 경우 null. + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path); + URL 개체 문자열 cdvfileURL의 문자열 표현을 = url.toString(); + + +플러그인 파일을 만들고 그것에 대 한 FileEntry 개체를 반환 하려면, 파일 플러그인을 사용. + + JSON 구조를 JavaScript에 반환을 위한 적당 한 반환 / /이 파일은 cdvfile URL로 표현 하는 경우 null. + JSONObject 항목 = filePlugin.getEntryForFile(file); + + +#### iOS + +IOS에서 코르도바 같은 사용 하지 않는 `CordovaResourceApi` 안 드 로이드 개념. Ios, Url 및 파일 시스템 경로 사이 변환 파일 플러그인을 사용 해야 합니다. + + URL 문자열 CDVFilesystemURL * url에서 CDVFilesystem URL 개체를 가져오기 = [CDVFilesystemURL fileSystemURLWithString:cdvfileURL]; + 파일 NSString * 경로에 매핑할 수 없는 경우 URL 개체 또는 없음에 대 한 경로 얻을 = [filePlugin filesystemPathForURL:url]; + + + 장치 경로 대 한 CDVFilesystem URL 개체를 가져오기 또는 / / 없음 cdvfile URL로 나타낼 수 없는 경우. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + URL 개체 NSString * cdvfileURL의 문자열 표현을 = [url absoluteString]; + + +플러그인 파일을 만들고 그것에 대 한 FileEntry 개체를 반환 하려면, 파일 플러그인을 사용. + + 장치 경로 대 한 CDVFilesystem URL 개체를 가져오기 또는 / / 없음 cdvfile URL로 나타낼 수 없는 경우. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + 자바 스크립트 NSDictionary * 항목으로 돌아가려면 구조를 얻을 = [filePlugin makeEntryForLocalURL:url] + + +#### 자바 스크립트 + +자바 스크립트에는 `cdvfile://` FileEntry 또는 DirectoryEntry 개체에서 URL 호출 `.toURL()` 그것에: + + var cdvfileURL = entry.toURL(); + + +플러그인 응답 처리기에서 실제 항목 개체로 반환 된 FileEntry 구조에서 변환 처리기 코드 해야 파일 플러그인 가져오고 새 개체를 만들: + + 적절 한 항목 개체 var 항목; + 경우 (entryStruct.isDirectory) {항목 = 새 DirectoryEntry (entryStruct.name, entryStruct.fullPath, 새로운 FileSystem(entryStruct.filesystemName));} 다른 {항목 = 새로운 FileEntry (entryStruct.name, entryStruct.fullPath, 새로운 FileSystem(entryStruct.filesystemName));} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/pl/README.md b/mobile/plugins/cordova-plugin-file/doc/pl/README.md new file mode 100644 index 0000000..166c3ce --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/pl/README.md @@ -0,0 +1,335 @@ + + +# cordova-plugin-file + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg)](https://travis-ci.org/apache/cordova-plugin-file) + +Ten plugin implementuje API pliku, dzięki czemu dostęp do odczytu i zapisu do plików znajdujących się na urządzeniu. + +Ten plugin jest oparty na kilka specyfikacje, w tym: HTML5 File API + +Katalogi (nieistniejącego już) i System Najnowsze rozszerzenia: , chociaż większość z ten plugin kod został napisany podczas wcześniejszych specyfikacji były aktualne: + +To również implementuje specyfikację FileWriter: + +Wykorzystania, prosimy odnieść się do skały HTML5 doskonałe [plików art.](http://www.html5rocks.com/en/tutorials/file/filesystem/) + +Omówienie innych opcji przechowywania odnoszą się do Cordova z [magazynu przewodnik](http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html). + +Ten plugin określa globalne `cordova.file` obiektu. + +Chociaż w globalnym zasięgu, to nie dostępne dopiero po `deviceready` imprezie. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## Instalacja + + cordova plugin add cordova-plugin-file + + +## Obsługiwane platformy + + * Amazon Fire OS + * Android + * BlackBerry 10 + * Firefox OS + * iOS + * Windows Phone 7 i 8 * + * Windows 8 * + * Windows* + * Przeglądarka + +\* *These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`.* + +## Gdzie przechowywać pliki + +Od v1.2.0 znajdują się adresy URL do katalogów ważne systemu plików. Każdy adres URL jest w formie *file:///path/to/spot/* i mogą być konwertowane na `DirectoryEntry` za pomocą `window.resolveLocalFileSystemURL()`. + + * `cordova.file.applicationDirectory`-Tylko do odczytu katalogu gdzie jest zainstalowana aplikacja. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.applicationStorageDirectory`-Katalogu obszaru izolowanego aplikacji; na iOS to miejsce jest tylko do odczytu (ale podkatalogów określonego [jak `/Documents` ] są odczytu i zapisu). Wszystkie dane zawarte w jest prywatną do aplikacji. ( *iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.dataDirectory`-Trwałe i prywatne dane magazynowanie w izolowanym aplikacji przy użyciu pamięci wewnętrznej (na Android, jeśli trzeba użyć zewnętrznej pamięci, należy użyć `.externalDataDirectory` ). Na iOS, Katalog ten nie jest zsynchronizowane z iCloud (za pomocą `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.cacheDirectory`-Katalog dla plików buforowanych danych lub pliki, które aplikacji ponownie można łatwo tworzyć. System operacyjny może usunąć te pliki, gdy urządzenie działa niski na przechowywanie, niemniej jednak aplikacje nie powinny polegać na OS, aby usunąć pliki tutaj. (*iOS*, *Android*, *BlackBerry 10*) + + * `cordova.file.externalApplicationStorageDirectory`-Stosowania przestrzeni na zewnętrznej pamięci masowej. (*Android*) + + * `cordova.file.externalDataDirectory`-Gdzie umieścić pliki danych specyficznych dla aplikacji na zewnętrznej pamięci masowej. (*Android*) + + * `cordova.file.externalCacheDirectory`-Pamięci podręcznej aplikacji na zewnętrznej pamięci masowej. (*Android*) + + * `cordova.file.externalRootDirectory`-Korzeń zewnętrznej pamięci masowej (karty SD). (*Android*, *BlackBerry 10*) + + * `cordova.file.tempDirectory`-Temp katalogu systemu operacyjnego można wyczyścić w będzie. Nie należy polegać na OS wobec usunąć ten katalog; aplikacji należy zawsze usunąć pliki jako obowiązujące. (*iOS*) + + * `cordova.file.syncedDataDirectory`-Posiada pliki specyficzne dla aplikacji, które powinny być zsynchronizowane (np. do iCloud). (*iOS*) + + * `cordova.file.documentsDirectory`-Pliki prywatne do aplikacji, ale że mają znaczenie dla innych aplikacji (np. plików pakietu Office). (*iOS*) + + * `cordova.file.sharedDirectory`-Pliki dostępne na całym świecie do wszystkich aplikacji (*BlackBerry 10*) + +## Plik System układy + +Chociaż technicznie implementacyjnym, może być bardzo przydatne wiedzieć, jak `cordova.file.*` właściwości mapy fizycznej ścieżki na prawdziwe urządzenie. + +### iOS układ systemu plików + +| Ścieżka urządzenia | `Cordova.File.*` | `iosExtraFileSystems` | r/w? | trwałe? | Czyści OS | Synchronizacja | prywatne | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:----:|:--------:|:-------------:|:--------------:|:--------:| +| `/ var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N/D! | N/D! | N/D! | Tak | +|    `appname.app/` | applicationDirectory | pakiet | r | N/D! | N/D! | N/D! | Tak | +|       `www/` | - | - | r | N/D! | N/D! | N/D! | Tak | +|    `Documents/` | documentsDirectory | dokumenty | r/w | Tak | Nr | Tak | Tak | +|       `NoCloud/` | - | dokumenty nosync | r/w | Tak | Nr | Nr | Tak | +|    `Library` | - | Biblioteka | r/w | Tak | Nr | Tak? | Tak | +|       `NoCloud/` | dataDirectory | Biblioteka nosync | r/w | Tak | Nr | Nr | Tak | +|       `Cloud/` | syncedDataDirectory | - | r/w | Tak | Nr | Tak | Tak | +|       `Caches/` | cacheDirectory | pamięci podręcznej | r/w | Tak * | Yes**\* | Nr | Tak | +|    `tmp/` | tempDirectory | - | r/w | No** | Yes**\* | Nr | Tak | + +\ * Pliki utrzymywały aplikacja zostanie ponownie uruchomiony i uaktualnienia, ale w tym katalogu mogą być rozliczone przy każdym OS pragnień. Aplikacji należy umożliwić odtworzenie treści, które mogą być usunięte. + +** Plików może utrzymywać się po ponownym uruchomieniu aplikacji, ale nie opierają się na tym zachowaniu. Pliki nie są gwarantowane w aktualizacji. Aplikacji należy usunąć pliki z tego katalogu, gdy ma to zastosowanie, ponieważ system operacyjny nie gwarantuje Kiedy (lub nawet jeśli) te pliki zostaną usunięte. + +**\ * System operacyjny może wyczyścić zawartość tego katalogu, gdy czuje, że jest to konieczne, ale nie powoływać się na to. Należy wyczyścić ten katalog jako odpowiednie dla aplikacji. + +### Układ systemu Android plików + +| Ścieżka urządzenia | `Cordova.File.*` | `AndroidExtraFileSystems` | r/w? | trwałe? | Czyści OS | prywatne | +|:------------------------------------------------ |:----------------------------------- |:------------------------------- |:----:|:-------:|:---------:|:--------:| +| `file:///android_asset/` | applicationDirectory | | r | N/D! | N/D! | Tak | +| `/Data/danych/< Aplikacja id > /` | applicationStorageDirectory | - | r/w | N/D! | N/D! | Tak | +|    `cache` | cacheDirectory | pamięci podręcznej | r/w | Tak | Yes\ * | Tak | +|    `files` | dataDirectory | pliki | r/w | Tak | Nr | Tak | +|       `Documents` | | dokumenty | r/w | Tak | Nr | Tak | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | Tak | Nr | Nr | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Tak | Nr | Nr | +|       `cache` | externalCacheDirectry | zewnętrznych pamięci podręcznej | r/w | Tak | No** | Nr | +|       `files` | externalDataDirectory | zewnętrznych plików | r/w | Tak | Nr | Nr | + +\ * OS może okresowo usunąć ten katalog, ale nie opierają się na tym zachowaniu. Wyczyść zawartość tego katalogu jako odpowiednie dla danej aplikacji. Należy użytkownik przeczyścić pamięć podręczną ręcznie, zawartość w tym katalogu są usuwane. + +** OS nie usunąć ten katalog automatycznie; Jesteś odpowiedzialny za zarządzanie zawartość siebie. Należy użytkownik przeczyścić pamięć podręczną ręcznie, zawartość katalogu są usuwane. + +**Uwaga**: Jeśli nie mogą być montowane pamięci masowej, właściwości `cordova.file.external*` są `wartości null`. + +### Układ systemu plików blackBerry 10 + +| Ścieżka urządzenia | `Cordova.File.*` | r/w? | trwałe? | Czyści OS | prywatne | +|:----------------------------------------------------------- |:--------------------------- |:----:|:-------:|:---------:|:--------:| +| `file:///accounts/1000/AppData/ < id aplikacji > /` | applicationStorageDirectory | r | N/D! | N/D! | Tak | +|    `app/native` | applicationDirectory | r | N/D! | N/D! | Tak | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | Nr | Tak | Tak | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Tak | Nr | Tak | +| `file:///accounts/1000/Removable/sdcard` | externalRemovableDirectory | r/w | Tak | Nr | Nr | +| `file:///accounts/1000/Shared` | sharedDirectory | r/w | Tak | Nr | Nr | + +*Uwaga*: gdy aplikacja jest rozmieszczana do pracy obwodu, wszystkie ścieżki są względne do /accounts/1000-enterprise. + +## Dziwactwa Androida + +### Lokalizacja przechowywania trwałych Android + +Istnieje wiele prawidłowe lokalizacje do przechowywania trwałych plików na telefonie z systemem Android. Zobacz [tę stronę](http://developer.android.com/guide/topics/data/data-storage.html) do szerokiej dyskusji o różnych możliwościach. + +Poprzednie wersje pluginu wybrać lokalizację plików tymczasowych i trwałe podczas uruchamiania, czy urządzenie twierdził, że karta SD (lub równoważne magazynowanie podzia³) był montowany w oparciu. Czy karta SD została zamontowana, czy duży wewnętrzny magazynowanie podzia³ był dostępny (takie jak na Nexus urządzenia,) a następnie trwałe pliki będą przechowywane w katalogu głównego tego miejsca. Oznaczało to, że wszystkie aplikacje Cordova może Zobacz wszystkie pliki dostępne na karcie. + +Jeśli karta SD nie był dostępny, a następnie poprzednie wersje będzie przechowywać dane w `/data/data/`, która izoluje aplikacje od siebie, ale nadal może spowodować danych, które mają być współużytkowane przez użytkowników. + +Teraz jest możliwe, aby zdecydować, czy do przechowywania plików w lokalizacji magazynu plików, lub przy użyciu poprzednich logiki, z preferencją w aplikacji w pliku `config.xml`. Aby to zrobić, Dodaj jedną z tych dwóch linii do `pliku config.xml`: + + + + + + +Bez tej linii wtyczki pliku będzie używać `Compatibility` jako domyślny. Jeśli znacznik preferencji jest obecny i to nie jedną z tych wartości, aplikacja nie zostanie uruchomiona. + +Jeśli aplikacja wcześniej zostało wysłane do użytkowników, przy użyciu starszych (pre-1.0) wersję tego pluginu i ma zapisane na dysku pliki w trwałych plików, a następnie należy ustawić preferencje do `Compatibility`. Przełączania lokalizacji do "Internal" oznacza, że istniejących użytkowników, którzy ich aplikacja może być niesłabnący wobec dostęp ich wcześniej zapisane pliki, w zależności od ich urządzenie. + +Jeśli aplikacja jest nowy, lub ma nigdy wcześniej przechowywane pliki w systemie plików trwałe, ustawienie `Internal` generalnie jest zalecane. + +### Powolny cyklicznych operacji dla /android_asset + +Lista katalogów aktywów jest bardzo powolny na Android. Można przyspieszyć to się jednak przez dodanie `src/android/build-extras.gradle` do katalogu głównego projektu android (również wymaga cordova-android@4.0.0 lub większej). + +## Dziwactwa iOS + + * `cordova.file.applicationStorageDirectory`jest tylko do odczytu; próby przechowywania plików w katalogu głównym zakończy się niepowodzeniem. Użyj jednego z innych `cordova.file.*` właściwości zdefiniowane dla iOS (tylko `applicationDirectory` i `applicationStorageDirectory` są tylko do odczytu). + * `FileReader.readAsText(blob, encoding)` + * `encoding`Parametr nie jest obsługiwana, i kodowanie UTF-8 jest zawsze w efekcie. + +### iOS lokalizacja przechowywania trwałych + +Istnieją dwa ważne miejsca trwałe pliki na urządzenia iOS: katalogu dokumentów i katalogu biblioteki. Poprzednie wersje pluginu tylko kiedykolwiek przechowywane trwałe pliki w katalogu dokumentów. To miał ten efekt uboczny od rozpoznawalności wszystkie pliki aplikacji w iTunes, który był często niezamierzone, zwłaszcza dla aplikacji, które obsługują wiele małych plików, zamiast produkuje kompletne dokumenty do wywozu, który jest przeznaczenie katalogu. + +Teraz jest możliwe, aby zdecydować, czy do przechowywania plików w dokumentach lub katalogu biblioteki, z preferencją w pliku `config.xml` aplikacji. Aby to zrobić, Dodaj jedną z tych dwóch linii do `pliku config.xml`: + + + + + + +Bez tej linii wtyczki pliku będzie używać `Compatibility` jako domyślny. Jeśli znacznik preferencji jest obecny i to nie jedną z tych wartości, aplikacja nie zostanie uruchomiona. + +Jeśli aplikacja wcześniej zostało wysłane do użytkowników, przy użyciu starszych (pre-1.0) wersję tego pluginu i ma zapisane na dysku pliki w trwałych plików, a następnie należy ustawić preferencje do `Compatibility`. Przełączania lokalizacji do `Library` oznaczałoby, że istniejących użytkowników, którzy ich aplikacja będzie niesłabnący wobec dostęp ich wcześniej zapisane pliki. + +Jeśli aplikacja jest nowy, lub nigdy wcześniej przechowywane pliki w trwałych plików, ustawień `Library` ogólnie jest zalecane. + +## Firefox OS dziwactwa + +API systemu plików nie jest obsługiwany macierzyście przez Firefox OS i jest zaimplementowany jako podkładki na indexedDB. + + * Nie usuwając niepuste katalogi + * Nie obsługuje metadane dla katalogów + * Metody `copyTo` i `moveTo` nie obsługuje katalogi + +Obsługiwane są następujące ścieżki danych: * `applicationDirectory` - używa `xhr`, aby uzyskać lokalne pliki, które są pakowane z aplikacji. * `dataDirectory` - na trwałe dane specyficzne dla aplikacji pliki. * `cacheDirectory` - buforowanych plików, które powinny przetrwać ponowne uruchomienie aplikacji (aplikacje nie powinny polegać na OS, aby usunąć pliki tutaj). + +## Quirks przeglądarki + +### Wspólne dziwactw i uwagi + + * Każda przeglądarka używa własnej piaskownicy plików. IE i Firefox Użyj IndexedDB jako podstawa. Wszystkie przeglądarki za pomocą ukośnika jako separatora katalogu ścieżka. + * Wpisy w katalogu mają być tworzone sukcesywnie. Na przykład wywołanie `fs.root.getDirectory (' dir1/dir2 ', {create:true}, successCallback, errorCallback)` zakończy się niepowodzeniem, jeśli nie istnieje dir1. + * Plugin żądania użytkownika uprawnień do używania trwałe przechowywanie przy pierwszym uruchomieniu aplikacji. + * Wtyczka obsługuje `cdvfile://localhost` (lokalne zasoby) tylko. Czyli zewnętrznych zasobów nie są obsługiwane przez `cdvfile`. + * Plugin nie następować po ["Plik API systemu nazw 8.3 ograniczenia"](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions). + * Obiektu BLOB i pliku "`close` funkcja nie jest obsługiwana. + * `FileSaver` i `BlobBuilder` nie są obsługiwane przez ten plugin i nie ma artykułów. + * Plugin nie obsługuje `requestAllFileSystems`. Ta funkcja jest również brak w specyfikacji. + * Wpisy w katalogu nie zostaną usunięte, jeśli używasz `create: true` flaga dla istniejącego katalogu. + * Pliki utworzone za pomocą konstruktora nie są obsługiwane. Zamiast tego należy użyć metody entry.file. + * Każda przeglądarka używa własnej postaci URL odwołania blob. + * `readAsDataURL` funkcja jest obsługiwana, ale mediatype w Chrome zależy od wejścia z rozszerzeniem, mediatype w IE zawsze jest pusty (który jest taki sam jak `zwykły tekst` według specyfikacji), mediatype w Firefox jest zawsze `aplikacji/oktet strumień`. Na przykład, jeśli treść jest `abcdefg` Firefox wraca z `danych: stosowanie / octet-stream, base64, YWJjZGVmZw ==`, czyli zwraca `danych:; base64, YWJjZGVmZw ==`, Chrome zwraca `danych: < mediatype w zależności od rozszerzenia nazwy; > base64, YWJjZGVmZw ==`. + * `toInternalURL` zwraca ścieżkę w postaci `file:///persistent/path/to/entry` (Firefox, IE). Chrom zwraca ścieżkę w postaci `cdvfile://localhost/persistent/file`. + +### Dziwactwa chrom + + * Chrom plików nie jest od razu gotowy po gotowe urządzenia. Jako rozwiązanie alternatywne można subskrybować zdarzenia `filePluginIsReady`. Przykład: + +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` + +Funkcja `window.isFilePluginReadyRaised` służy do sprawdzenia, czy zdarzenie już została podniesiona. -kwoty plików tymczasowych i trwałe window.requestFileSystem nie są ograniczone w Chrome. -W celu zwiększenia trwałego magazynu w Chrome, należy wywołać metodę `window.initPersistentFileSystem`. Domyślnie trwałe dyskowa jest 5 MB. -Chrome wymaga `--pozwalają--dostęp z plików` uruchomić argument na poparcie API za pośrednictwem protokołu `file:///`. -`Plik` obiekt będzie nie zmieniło jeśli flaga `{create:true}` gdy już istniejący `wpis`. -wydarzenia `zwrotu` właściwość jest zestaw true w Chrome. Jest to sprzeczne ze [specyfikacji](http://dev.w3.org/2009/dap/file-system/file-writer.html). -Funkcja `toURL` w Chrome zwraca `plików:`-poprzedzona ścieżką w zależności od aplikacji hosta. Na przykład, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -wynik funkcji `toURL` nie zawierają ukośnika w wpis w katalogu. Chrom usuwa katalogi z ciąć doczepiane adresów URL poprawnie choć. -Metoda `resolveLocalFileSystemURL` wymaga przychodzących `url` mają prefiks `plików`. Na przykład parametr `adresu url` do `resolveLocalFileSystemURL` powinny być w formie `filesystem:file:///persistent/somefile.txt`, w przeciwieństwie do formularza `file:///persistent/somefile.txt` w Android. -Przestarzałe `toNativeURL` funkcja nie jest obsługiwana i nie tylko. -Funkcja `setMetadata` jest nie podane w specyfikacji i nie jest obsługiwane. -INVALID_MODIFICATION_ERR (kod: 9) jest generowany zamiast SYNTAX_ERR(code: 8) na żądanie nieistniejącą plików. -INVALID_MODIFICATION_ERR (kod: 9) jest generowany zamiast PATH_EXISTS_ERR(code: 12) próbuje stworzyć wyłącznie pliku lub katalogu, który już istnieje. -INVALID_MODIFICATION_ERR (kod: 9) jest generowany zamiast NO_MODIFICATION_ALLOWED_ERR(code: 6) na próby wywołania removeRecursively w głównym systemie plików. -INVALID_MODIFICATION_ERR (kod: 9) jest generowany zamiast NOT_FOUND_ERR(code: 1) na trudny do katalogu moveTo, który nie istnieje. + +### Na bazie IndexedDB impl dziwactw (Firefox i IE) + + * `.` i `.` nie są obsługiwane. + * IE obsługuje `file:///`-tryb; tylko obsługiwane tryb jest obsługiwany (http://localhost:xxxx). + * Rozmiar plików Firefox nie jest ograniczona, ale każde rozszerzenie 50MB zwróci użytkownikowi uprawnienia. IE10 pozwala maksymalnie 10mb połączone "appcache" i IndexedDB używane w implementacji systemu plików bez monitowania, gdy trafisz na tym poziomie, które uzyskasz, jeśli chcesz mogła ona zostać zwiększony do max 250mb na stronie. Więc `rozmiar` parametru funkcja `requestFileSystem` nie wpływa na system plików Firefox i IE. + * `readAsBinaryString` funkcja nie jest określona w specyfikacji i nie obsługiwane w IE i nie tylko. + * `File.Type` ma zawsze wartość null. + * Nie należy utworzyć wpis za pomocą DirectoryEntry wystąpienie wynik wywołania zwrotnego, który został usunięty. W przeciwnym razie dostaniesz wpisem"wiszące". + * Zanim będzie można przeczytać plik, który został napisany tylko trzeba uzyskać nowe wystąpienie tego pliku. + * Funkcja `setMetadata`, która nie jest określona w specyfikacji obsługuje tylko zmian pola `modificationTime`. + * `copyTo` i `moveTo` funkcji nie obsługuje katalogi. + * Metadanych w katalogów nie jest obsługiwana. + * Zarówno Entry.remove i directoryEntry.removeRecursively nie usuwając niepuste katalogi - katalogi są usuwane są czyszczone z treści zamiast. + * `abort` i `truncate` funkcje nie są obsługiwane. + * zdarzenia postępu nie są zwalniani. Na przykład to obsługa będzie nie wykonywane: + +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## Uaktualniania notatek + +W v1.0.0 tego pluginu struktury `FileEntry` i `DirectoryEntry` zmieniły się więcej zgodnie z opublikowaną specyfikacją. + +Poprzednie wersje (pre-1.0.0) plugin przechowywane urządzenia bezwzględna plik lokalizacja we właściwości `fullPath` `wpis` obiektów. Te ścieżki zazwyczaj będzie wyglądać + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Te ścieżki były także zwracany przez metodę `toURL()` `Entry` obiektów. + +Z v1.0.0 atrybut `fullPath` jest ścieżką do pliku, *względem katalogu głównego systemu plików HTML*. Tak powyżej ścieżki będzie teraz zarówno być reprezentowane przez obiekt `FileEntry` z `fullPath` o + + /path/to/file + + +Jeśli aplikacja działa z ścieżki bezwzględnej urządzeń, i możesz wcześniej źródło tych ścieżek przez właściwość `fullPath` `wpis` obiektów, należy zaktualizować kod, aby zamiast tego użyj `entry.toURL()`. + +Dla wstecznej kompatybilności, Metoda `resolveLocalFileSystemURL()` będzie zaakceptować urządzenia ścieżka bezwzględna i zwróci obiekt `Entry` odpowiadający, tak długo, jak ten plik istnieje w albo `TEMPORARY` lub `PERSISTENT` systemy plików. + +To szczególnie został problem z pluginem transferu plików, które poprzednio używane ścieżki bezwzględnej urządzeń (i wciąż można je przyjąć). Została zaktualizowana do pracy poprawnie z adresów URL plików, więc wymiana `entry.fullPath` z `entry.toURL()` powinno rozwiązać wszelkie problemy dostawanie ten plugin do pracy z plików w pamięci urządzenia. + +W v1.1.0 wartość zwracana przez `toURL()` został zmieniony (patrz \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) zwraca adres URL absolutnej "file://". wszędzie tam, gdzie jest to możliwe. Aby zapewnić ' cdvfile:'-URL można użyć `toInternalURL()` teraz. Ta metoda zwróci teraz adresy URL plików formularza + + cdvfile://localhost/persistent/path/to/file + + +który służy do jednoznacznej identyfikacji pliku. + +## Wykaz kodów błędów i ich znaczenie + +Gdy błąd jest generowany, jeden z następujących kodów będzie służyć. + +| Kod | Stała | +| ---:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Konfigurowanie wtyczka (opcjonalny) + +Zestaw dostępnych plików może być skonfigurowany na platformie. Zarówno iOS i Android Tag w `pliku config.xml`, których nazwy plików do instalacji. Domyślnie włączone są wszystkie korzenie systemu plików. + + + + + +### Android + + * `files`: katalogu przechowywania plików aplikacji + * `files-external`: katalog aplikacji zewnętrznych plików + * `sdcard`: katalog globalny plik zewnętrzny (to jest głównym karty SD, jeśli jedna jest zainstalowana). Musi mieć uprawnienia `android.permission.WRITE_EXTERNAL_STORAGE` wobec używać ten. + * `cache`: katalogu wewnętrznej pamięci podręcznej aplikacji + * `cache-external`: katalogu aplikacji zewnętrznych pamięci podręcznej + * `root`: całe urządzenie systemu plików + +Android obsługuje również specjalnych plików o nazwie "dokumenty", który reprezentuje podkatalog "/ dokumenty /" w ramach systemu plików "pliki". + +### iOS + + * `library`: katalog biblioteki aplikacji + * `documents`: dokumenty katalogu aplikacji + * `cache`: katalogu pamięci podręcznej aplikacji + * `bundle`: pakiet aplikacji; Lokalizacja aplikacji na dysku (tylko do odczytu) + * `root`: całe urządzenie systemu plików + +Domyślnie katalogi biblioteki i dokumenty mogą być synchronizowane iCloud. Można również zażądać dwóch dodatkowych plików, `library-nosync` i `documents-nosync`, które stanowią specjalny katalog nie zsynchronizowane w `/Library` lub systemu plików `/Documents`. \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/pl/index.md b/mobile/plugins/cordova-plugin-file/doc/pl/index.md new file mode 100644 index 0000000..1ccb330 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/pl/index.md @@ -0,0 +1,338 @@ + + +# cordova-plugin-file + +Ten plugin implementuje API pliku, dzięki czemu dostęp do odczytu i zapisu do plików znajdujących się na urządzeniu. + +Ten plugin jest oparty na kilka specyfikacje, w tym: HTML5 File API + +Katalogi (nieistniejącego już) i System Najnowsze rozszerzenia: , chociaż większość z ten plugin kod został napisany podczas wcześniejszych specyfikacji były aktualne: + +To również implementuje specyfikację FileWriter: + +Wykorzystania, prosimy odnieść się do skały HTML5 doskonałe [plików art.][1] + + [1]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +Omówienie innych opcji przechowywania odnoszą się do Cordova z [magazynu przewodnik][2]. + + [2]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +Ten plugin określa globalne `cordova.file` obiektu. + +Chociaż w globalnym zasięgu, to nie dostępne dopiero po `deviceready` imprezie. + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## Instalacja + + cordova plugin add cordova-plugin-file + + +## Obsługiwane platformy + +* Amazon Fire OS +* Android +* BlackBerry 10 +* Firefox OS +* iOS +* Windows Phone 7 i 8 * +* Windows 8 * +* Przeglądarka + +* *Nie obsługują tych platform, `FileReader.readAsArrayBuffer` ani `FileWriter.write(blob)`.* + +## Gdzie przechowywać pliki + +Od v1.2.0 znajdują się adresy URL do katalogów ważne systemu plików. Każdy adres URL jest w formie *file:///path/to/spot/* i mogą być konwertowane na `DirectoryEntry` za pomocą `window.resolveLocalFileSystemURL()`. + +* `cordova.file.applicationDirectory`-Tylko do odczytu katalogu gdzie jest zainstalowana aplikacja. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.applicationStorageDirectory`-Katalogu obszaru izolowanego aplikacji; na iOS to miejsce jest tylko do odczytu (ale podkatalogów określonego [jak `/Documents` ] są odczytu i zapisu). Wszystkie dane zawarte w jest prywatną do aplikacji. ( *iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.dataDirectory`-Trwałe i prywatne dane magazynowanie w izolowanym aplikacji przy użyciu pamięci wewnętrznej (na Android, jeśli trzeba użyć zewnętrznej pamięci, należy użyć `.externalDataDirectory` ). Na iOS, Katalog ten nie jest zsynchronizowane z iCloud (za pomocą `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.cacheDirectory`-Katalog dla plików buforowanych danych lub pliki, które aplikacji ponownie można łatwo tworzyć. System operacyjny może usunąć te pliki, gdy urządzenie działa niski na przechowywanie, niemniej jednak aplikacje nie powinny polegać na OS, aby usunąć pliki tutaj. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.externalApplicationStorageDirectory`-Stosowania przestrzeni na zewnętrznej pamięci masowej. (*Android*) + +* `cordova.file.externalDataDirectory`-Gdzie umieścić pliki danych specyficznych dla aplikacji na zewnętrznej pamięci masowej. (*Android*) + +* `cordova.file.externalCacheDirectory`-Pamięci podręcznej aplikacji na zewnętrznej pamięci masowej. (*Android*) + +* `cordova.file.externalRootDirectory`-Korzeń zewnętrznej pamięci masowej (karty SD). (*Android*, *BlackBerry 10*) + +* `cordova.file.tempDirectory`-Temp katalogu systemu operacyjnego można wyczyścić w będzie. Nie należy polegać na OS wobec usunąć ten katalog; aplikacji należy zawsze usunąć pliki jako obowiązujące. (*iOS*) + +* `cordova.file.syncedDataDirectory`-Posiada pliki specyficzne dla aplikacji, które powinny być zsynchronizowane (np. do iCloud). (*iOS*) + +* `cordova.file.documentsDirectory`-Pliki prywatne do aplikacji, ale że mają znaczenie dla innych aplikacji (np. plików pakietu Office). (*iOS*) + +* `cordova.file.sharedDirectory`-Pliki dostępne na całym świecie do wszystkich aplikacji (*BlackBerry 10*) + +## Plik System układy + +Chociaż technicznie implementacyjnym, może być bardzo przydatne wiedzieć, jak `cordova.file.*` właściwości mapy fizycznej ścieżki na prawdziwe urządzenie. + +### iOS układ systemu plików + +| Ścieżka urządzenia | `Cordova.File.*` | `iosExtraFileSystems` | r/w? | trwałe? | Czyści OS | Synchronizacja | prywatne | +|:-------------------------------------------- |:--------------------------- |:--------------------- |:----:|:-------:|:-----------:|:--------------:|:--------:| +| `/ var/mobile/Applications/< UUID > /` | applicationStorageDirectory | - | r | N/D! | N/D! | N/D! | Tak | +|    `appname.app/` | applicationDirectory | pakiet | r | N/D! | N/D! | N/D! | Tak | +|       `www/` | - | - | r | N/D! | N/D! | N/D! | Tak | +|    `Documents/` | documentsDirectory | dokumenty | r/w | Tak | Nr | Tak | Tak | +|       `NoCloud/` | - | dokumenty nosync | r/w | Tak | Nr | Nr | Tak | +|    `Library` | - | Biblioteka | r/w | Tak | Nr | Tak? | Tak | +|       `NoCloud/` | dataDirectory | Biblioteka nosync | r/w | Tak | Nr | Nr | Tak | +|       `Cloud/` | syncedDataDirectory | - | r/w | Tak | Nr | Tak | Tak | +|       `Caches/` | cacheDirectory | pamięci podręcznej | r/w | Tak * | Tak * * *| | Nr | Tak | +|    `tmp/` | tempDirectory | - | r/w | Nie * * | Tak * * *| | Nr | Tak | + +* Pliki utrzymywały aplikacja zostanie ponownie uruchomiony i uaktualnienia, ale w tym katalogu mogą być rozliczone, gdy OS pragnienia. Aplikacji powinny być w stanie odtworzyć zawartość, która może być usunięta. + +* * Plików może utrzymywać się po ponownym uruchomieniu aplikacji, ale nie opierają się na tym zachowaniu. Pliki nie są gwarantowane w aktualizacji. Aplikacji należy usunąć pliki z tego katalogu, gdy ma to zastosowanie, ponieważ system operacyjny nie gwarantuje Kiedy (lub nawet jeśli) te pliki zostaną usunięte. + +* * *| System operacyjny może wyczyścić zawartość w tym katalogu, gdy czuje, że jest to konieczne, ale nie powoływać się na to. Należy wyczyścić ten katalog jako odpowiednie dla aplikacji. + +### Układ systemu Android plików + +| Ścieżka urządzenia | `Cordova.File.*` | `AndroidExtraFileSystems` | r/w? | trwałe? | Czyści OS | prywatne | +|:--------------------------------------- |:----------------------------------- |:------------------------------- |:----:|:-------:|:---------:|:--------:| +| `file:///android_asset/` | applicationDirectory | | r | N/D! | N/D! | Tak | +| `/Data/danych/< Aplikacja id > /` | applicationStorageDirectory | - | r/w | N/D! | N/D! | Tak | +|    `cache` | cacheDirectory | pamięci podręcznej | r/w | Tak | Tak * | Tak | +|    `files` | dataDirectory | pliki | r/w | Tak | Nr | Tak | +|       `Documents` | | dokumenty | r/w | Tak | Nr | Tak | +| `< sdcard > /` | externalRootDirectory | sdcard | r/w | Tak | Nr | Nr | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Tak | Nr | Nr | +|       `cache` | externalCacheDirectry | zewnętrznych pamięci podręcznej | r/w | Tak | Nie * * | Nr | +|       `files` | externalDataDirectory | zewnętrznych plików | r/w | Tak | Nr | Nr | + +* System operacyjny może okresowo usunąć ten katalog, ale nie opierają się na tym zachowaniu. Wyczyść zawartość tego katalogu jako odpowiednie dla danej aplikacji. Należy użytkownik przeczyścić pamięć podręczną ręcznie, zawartość w tym katalogu są usuwane. + +* * System operacyjny nie usunąć ten katalog automatycznie; Jesteś odpowiedzialny za zarządzanie zawartość siebie. Należy użytkownik przeczyścić pamięć podręczną ręcznie, zawartość katalogu są usuwane. + +**Uwaga**: Jeśli nie mogą być montowane pamięci masowej, właściwości `cordova.file.external*` są `wartości null`. + +### Układ systemu plików blackBerry 10 + +| Ścieżka urządzenia | `Cordova.File.*` | r/w? | trwałe? | Czyści OS | prywatne | +|:--------------------------------------------------------- |:--------------------------- |:----:|:-------:|:---------:|:--------:| +| `file:///accounts/1000/AppData/ < id aplikacji > /` | applicationStorageDirectory | r | N/D! | N/D! | Tak | +|    `app/native` | applicationDirectory | r | N/D! | N/D! | Tak | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | Nr | Tak | Tak | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Tak | Nr | Tak | +| `file:///accounts/1000/Removable/sdcard` | externalRemovableDirectory | r/w | Tak | Nr | Nr | +| `file:///accounts/1000/Shared` | sharedDirectory | r/w | Tak | Nr | Nr | + +*Uwaga*: gdy aplikacja jest rozmieszczana do pracy obwodu, wszystkie ścieżki są względne do /accounts/1000-enterprise. + +## Dziwactwa Androida + +### Lokalizacja przechowywania trwałych Android + +Istnieje wiele prawidłowe lokalizacje do przechowywania trwałych plików na telefonie z systemem Android. Zobacz [tę stronę][3] do szerokiej dyskusji o różnych możliwościach. + + [3]: http://developer.android.com/guide/topics/data/data-storage.html + +Poprzednie wersje pluginu wybrać lokalizację plików tymczasowych i trwałe podczas uruchamiania, czy urządzenie twierdził, że karta SD (lub równoważne magazynowanie podzia³) był montowany w oparciu. Czy karta SD została zamontowana, czy duży wewnętrzny magazynowanie podzia³ był dostępny (takie jak na Nexus urządzenia,) a następnie trwałe pliki będą przechowywane w katalogu głównego tego miejsca. Oznaczało to, że wszystkie aplikacje Cordova może Zobacz wszystkie pliki dostępne na karcie. + +Jeśli karta SD nie był dostępny, a następnie poprzednie wersje będzie przechowywać dane w `/data/data/`, która izoluje aplikacje od siebie, ale nadal może spowodować danych, które mają być współużytkowane przez użytkowników. + +Teraz jest możliwe, aby zdecydować, czy do przechowywania plików w lokalizacji magazynu plików, lub przy użyciu poprzednich logiki, z preferencją w aplikacji w pliku `config.xml`. Aby to zrobić, Dodaj jedną z tych dwóch linii do `pliku config.xml`: + + + + + + +Bez tej linii wtyczki pliku będzie używać `Compatibility` jako domyślny. Jeśli znacznik preferencji jest obecny i to nie jedną z tych wartości, aplikacja nie zostanie uruchomiona. + +Jeśli aplikacja wcześniej zostało wysłane do użytkowników, przy użyciu starszych (pre-1.0) wersję tego pluginu i ma zapisane na dysku pliki w trwałych plików, a następnie należy ustawić preferencje do `Compatibility`. Przełączania lokalizacji do "Internal" oznacza, że istniejących użytkowników, którzy ich aplikacja może być niesłabnący wobec dostęp ich wcześniej zapisane pliki, w zależności od ich urządzenie. + +Jeśli aplikacja jest nowy, lub ma nigdy wcześniej przechowywane pliki w systemie plików trwałe, ustawienie `Internal` generalnie jest zalecane. + +## Dziwactwa iOS + +* `cordova.file.applicationStorageDirectory`jest tylko do odczytu; próby przechowywania plików w katalogu głównym zakończy się niepowodzeniem. Użyj jednego z innych `cordova.file.*` właściwości zdefiniowane dla iOS (tylko `applicationDirectory` i `applicationStorageDirectory` są tylko do odczytu). +* `FileReader.readAsText(blob, encoding)` + * `encoding`Parametr nie jest obsługiwana, i kodowanie UTF-8 jest zawsze w efekcie. + +### iOS lokalizacja przechowywania trwałych + +Istnieją dwa ważne miejsca trwałe pliki na urządzenia iOS: katalogu dokumentów i katalogu biblioteki. Poprzednie wersje pluginu tylko kiedykolwiek przechowywane trwałe pliki w katalogu dokumentów. To miał ten efekt uboczny od rozpoznawalności wszystkie pliki aplikacji w iTunes, który był często niezamierzone, zwłaszcza dla aplikacji, które obsługują wiele małych plików, zamiast produkuje kompletne dokumenty do wywozu, który jest przeznaczenie katalogu. + +Teraz jest możliwe, aby zdecydować, czy do przechowywania plików w dokumentach lub katalogu biblioteki, z preferencją w pliku `config.xml` aplikacji. Aby to zrobić, Dodaj jedną z tych dwóch linii do `pliku config.xml`: + + + + + + +Bez tej linii wtyczki pliku będzie używać `Compatibility` jako domyślny. Jeśli znacznik preferencji jest obecny i to nie jedną z tych wartości, aplikacja nie zostanie uruchomiona. + +Jeśli aplikacja wcześniej zostało wysłane do użytkowników, przy użyciu starszych (pre-1.0) wersję tego pluginu i ma zapisane na dysku pliki w trwałych plików, a następnie należy ustawić preferencje do `Compatibility`. Przełączania lokalizacji do `Library` oznaczałoby, że istniejących użytkowników, którzy ich aplikacja będzie niesłabnący wobec dostęp ich wcześniej zapisane pliki. + +Jeśli aplikacja jest nowy, lub nigdy wcześniej przechowywane pliki w trwałych plików, ustawień `Library` ogólnie jest zalecane. + +## Firefox OS dziwactwa + +API systemu plików nie jest obsługiwany macierzyście przez Firefox OS i jest zaimplementowany jako podkładki na indexedDB. + +* Nie usuwając niepuste katalogi +* Nie obsługuje metadane dla katalogów +* Metody `copyTo` i `moveTo` nie obsługuje katalogi + +Obsługiwane są następujące ścieżki danych: * `applicationDirectory` - używa `xhr`, aby uzyskać lokalne pliki, które są pakowane z aplikacji. * `dataDirectory` - na trwałe dane specyficzne dla aplikacji pliki. * `cacheDirectory` - buforowanych plików, które powinny przetrwać ponowne uruchomienie aplikacji (aplikacje nie powinny polegać na OS, aby usunąć pliki tutaj). + +## Quirks przeglądarki + +### Wspólne dziwactw i uwagi + +* Każda przeglądarka używa własnej piaskownicy plików. IE i Firefox Użyj IndexedDB jako podstawa. Wszystkie przeglądarki za pomocą ukośnika jako separatora katalogu ścieżka. +* Wpisy w katalogu mają być tworzone sukcesywnie. Na przykład wywołanie `fs.root.getDirectory (' dir1/dir2 ', {create:true}, successCallback, errorCallback)` zakończy się niepowodzeniem, jeśli nie istnieje dir1. +* Plugin żądania użytkownika uprawnień do używania trwałe przechowywanie przy pierwszym uruchomieniu aplikacji. +* Wtyczka obsługuje `cdvfile://localhost` (lokalne zasoby) tylko. Czyli zewnętrznych zasobów nie są obsługiwane przez `cdvfile`. +* Plugin nie następować po ["Plik API systemu nazw 8.3 ograniczenia"][4]. +* Obiektu BLOB i pliku "`close` funkcja nie jest obsługiwana. +* `FileSaver` i `BlobBuilder` nie są obsługiwane przez ten plugin i nie ma artykułów. +* Plugin nie obsługuje `requestAllFileSystems`. Ta funkcja jest również brak w specyfikacji. +* Wpisy w katalogu nie zostaną usunięte, jeśli używasz `create: true` flaga dla istniejącego katalogu. +* Pliki utworzone za pomocą konstruktora nie są obsługiwane. Zamiast tego należy użyć metody entry.file. +* Każda przeglądarka używa własnej postaci URL odwołania blob. +* `readAsDataURL` funkcja jest obsługiwana, ale mediatype w Chrome zależy od wejścia z rozszerzeniem, mediatype w IE zawsze jest pusty (który jest taki sam jak `zwykły tekst` według specyfikacji), mediatype w Firefox jest zawsze `aplikacji/oktet strumień`. Na przykład, jeśli treść jest `abcdefg` Firefox wraca z `danych: stosowanie / octet-stream, base64, YWJjZGVmZw ==`, czyli zwraca `danych:; base64, YWJjZGVmZw ==`, Chrome zwraca `danych: < mediatype w zależności od rozszerzenia nazwy; > base64, YWJjZGVmZw ==`. +* `toInternalURL` zwraca ścieżkę w postaci `file:///persistent/path/to/entry` (Firefox, IE). Chrom zwraca ścieżkę w postaci `cdvfile://localhost/persistent/file`. + + [4]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions + +### Dziwactwa chrom + +* Chrom plików nie jest od razu gotowy po gotowe urządzenia. Jako rozwiązanie alternatywne można subskrybować zdarzenia `filePluginIsReady`. Przykład: + + javascript + window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); + + +Funkcja `window.isFilePluginReadyRaised` służy do sprawdzenia, czy zdarzenie już została podniesiona. -kwoty plików tymczasowych i trwałe window.requestFileSystem nie są ograniczone w Chrome. -W celu zwiększenia trwałego magazynu w Chrome, należy wywołać metodę `window.initPersistentFileSystem`. Domyślnie trwałe dyskowa jest 5 MB. -Chrome wymaga `--pozwalają--dostęp z plików` uruchomić argument na poparcie API za pośrednictwem protokołu `file:///`. -`Plik` obiekt będzie nie zmieniło jeśli flaga `{create:true}` gdy już istniejący `wpis`. -wydarzenia `zwrotu` właściwość jest zestaw true w Chrome. Jest to sprzeczne ze [specyfikacji][5]. -Funkcja `toURL` w Chrome zwraca `plików:`-poprzedzona ścieżką w zależności od aplikacji hosta. Na przykład, `filesystem:file:///persistent/somefile.txt`, `filesystem:http://localhost:8080/persistent/somefile.txt`. -wynik funkcji `toURL` nie zawierają ukośnika w wpis w katalogu. Chrom usuwa katalogi z ciąć doczepiane adresów URL poprawnie choć. -Metoda `resolveLocalFileSystemURL` wymaga przychodzących `url` mają prefiks `plików`. Na przykład parametr `adresu url` do `resolveLocalFileSystemURL` powinny być w formie `filesystem:file:///persistent/somefile.txt`, w przeciwieństwie do formularza `file:///persistent/somefile.txt` w Android. -Przestarzałe `toNativeURL` funkcja nie jest obsługiwana i nie tylko. -Funkcja `setMetadata` jest nie podane w specyfikacji i nie jest obsługiwane. -INVALID_MODIFICATION_ERR (kod: 9) jest generowany zamiast SYNTAX_ERR(code: 8) na żądanie nieistniejącą plików. -INVALID_MODIFICATION_ERR (kod: 9) jest generowany zamiast PATH_EXISTS_ERR(code: 12) próbuje stworzyć wyłącznie pliku lub katalogu, który już istnieje. -INVALID_MODIFICATION_ERR (kod: 9) jest generowany zamiast NO_MODIFICATION_ALLOWED_ERR(code: 6) na próby wywołania removeRecursively w głównym systemie plików. -INVALID_MODIFICATION_ERR (kod: 9) jest generowany zamiast NOT_FOUND_ERR(code: 1) na trudny do katalogu moveTo, który nie istnieje. + + [5]: http://dev.w3.org/2009/dap/file-system/file-writer.html + +### Na bazie IndexedDB impl dziwactw (Firefox i IE) + +* `.` i `.` nie są obsługiwane. +* IE obsługuje `file:///`-tryb; tylko obsługiwane tryb jest obsługiwany (http://localhost:xxxx). +* Rozmiar plików Firefox nie jest ograniczona, ale każde rozszerzenie 50MB zwróci użytkownikowi uprawnienia. IE10 pozwala maksymalnie 10mb połączone "appcache" i IndexedDB używane w implementacji systemu plików bez monitowania, gdy trafisz na tym poziomie, które uzyskasz, jeśli chcesz mogła ona zostać zwiększony do max 250mb na stronie. Więc `rozmiar` parametru funkcja `requestFileSystem` nie wpływa na system plików Firefox i IE. +* `readAsBinaryString` funkcja nie jest określona w specyfikacji i nie obsługiwane w IE i nie tylko. +* `File.Type` ma zawsze wartość null. +* Nie należy utworzyć wpis za pomocą DirectoryEntry wystąpienie wynik wywołania zwrotnego, który został usunięty. W przeciwnym razie dostaniesz wpisem"wiszące". +* Zanim będzie można przeczytać plik, który został napisany tylko trzeba uzyskać nowe wystąpienie tego pliku. +* Funkcja `setMetadata`, która nie jest określona w specyfikacji obsługuje tylko zmian pola `modificationTime`. +* `copyTo` i `moveTo` funkcji nie obsługuje katalogi. +* Metadanych w katalogów nie jest obsługiwana. +* Zarówno Entry.remove i directoryEntry.removeRecursively nie usuwając niepuste katalogi - katalogi są usuwane są czyszczone z treści zamiast. +* `abort` i `truncate` funkcje nie są obsługiwane. +* zdarzenia postępu nie są zwalniani. Na przykład to obsługa będzie nie wykonywane: + + javascript + writer.onprogress = function() { /*commands*/ }; + + +## Uaktualniania notatek + +W v1.0.0 tego pluginu struktury `FileEntry` i `DirectoryEntry` zmieniły się więcej zgodnie z opublikowaną specyfikacją. + +Poprzednie wersje (pre-1.0.0) plugin przechowywane urządzenia bezwzględna plik lokalizacja we właściwości `fullPath` `wpis` obiektów. Te ścieżki zazwyczaj będzie wyglądać + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Te ścieżki były także zwracany przez metodę `toURL()` `Entry` obiektów. + +Z v1.0.0 atrybut `fullPath` jest ścieżką do pliku, *względem katalogu głównego systemu plików HTML*. Tak powyżej ścieżki będzie teraz zarówno być reprezentowane przez obiekt `FileEntry` z `fullPath` o + + /path/to/file + + +Jeśli aplikacja działa z ścieżki bezwzględnej urządzeń, i możesz wcześniej źródło tych ścieżek przez właściwość `fullPath` `wpis` obiektów, należy zaktualizować kod, aby zamiast tego użyj `entry.toURL()`. + +Dla wstecznej kompatybilności, Metoda `resolveLocalFileSystemURL()` będzie zaakceptować urządzenia ścieżka bezwzględna i zwróci obiekt `Entry` odpowiadający, tak długo, jak ten plik istnieje w albo `TEMPORARY` lub `PERSISTENT` systemy plików. + +To szczególnie został problem z pluginem transferu plików, które poprzednio używane ścieżki bezwzględnej urządzeń (i wciąż można je przyjąć). Została zaktualizowana do pracy poprawnie z adresów URL plików, więc wymiana `entry.fullPath` z `entry.toURL()` powinno rozwiązać wszelkie problemy dostawanie ten plugin do pracy z plików w pamięci urządzenia. + +W v1.1.0 wartość zwracana przez `toURL()` został zmieniony (patrz \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) zwraca adres URL absolutnej "file://". wszędzie tam, gdzie jest to możliwe. Aby zapewnić ' cdvfile:'-URL można użyć `toInternalURL()` teraz. Ta metoda zwróci teraz adresy URL plików formularza + + cdvfile://localhost/persistent/path/to/file + + +który służy do jednoznacznej identyfikacji pliku. + +## Wykaz kodów błędów i ich znaczenie + +Gdy błąd jest generowany, jeden z następujących kodów będzie służyć. + +| Kod | Stała | +| ---:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Konfigurowanie wtyczka (opcjonalny) + +Zestaw dostępnych plików może być skonfigurowany na platformie. Zarówno iOS i Android Tag w `pliku config.xml`, których nazwy plików do instalacji. Domyślnie włączone są wszystkie korzenie systemu plików. + + + + + +### Android + +* `files`: katalogu przechowywania plików aplikacji +* `files-external`: katalog aplikacji zewnętrznych plików +* `sdcard`: katalog globalny plik zewnętrzny (to jest głównym karty SD, jeśli jedna jest zainstalowana). Musi mieć uprawnienia `android.permission.WRITE_EXTERNAL_STORAGE` wobec używać ten. +* `cache`: katalogu wewnętrznej pamięci podręcznej aplikacji +* `cache-external`: katalogu aplikacji zewnętrznych pamięci podręcznej +* `root`: całe urządzenie systemu plików + +Android obsługuje również specjalnych plików o nazwie "dokumenty", który reprezentuje podkatalog "/ dokumenty /" w ramach systemu plików "pliki". + +### iOS + +* `library`: katalog biblioteki aplikacji +* `documents`: dokumenty katalogu aplikacji +* `cache`: katalogu pamięci podręcznej aplikacji +* `bundle`: pakiet aplikacji; Lokalizacja aplikacji na dysku (tylko do odczytu) +* `root`: całe urządzenie systemu plików + +Domyślnie katalogi biblioteki i dokumenty mogą być synchronizowane iCloud. Można również zażądać dwóch dodatkowych plików, `library-nosync` i `documents-nosync`, które stanowią specjalny katalog nie zsynchronizowane w `/Library` lub systemu plików `/Documents`. diff --git a/mobile/plugins/cordova-plugin-file/doc/pl/plugins.md b/mobile/plugins/cordova-plugin-file/doc/pl/plugins.md new file mode 100644 index 0000000..6e8fe86 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/pl/plugins.md @@ -0,0 +1,101 @@ + + +# Uwagi dla programistów wtyczki + +Te notatki są przeznaczone przede wszystkim dla Androida i iOS deweloperów, którzy chcieli pisac pluginy które interfejs z systemu plików za pomocą wtyczki pliku. + +## Praca z Cordova pliku system adresów URL + +Od wersji 1.0.0, ten plugin ma używane adresy URL z `cdvfile` system dla wszystkich komunikacji przez most, a nie narażać urządzenia raw ścieżki systemu plików JavaScript. + +Na stronie JavaScript oznacza to, że FileEntry i DirectoryEntry obiekty mają fullPath atrybut, który jest głównym systemie plików HTML. Jeśli twój plugin JavaScript API akceptuje obiektu FileEntry lub DirectoryEntry, należy zadzwonić `.toURL()` dla tego obiektu przed przekazaniem Altpradl do kodu macierzystego. + +### Konwersja cdvfile: / / URL do ścieżki fileystem + +Wtyczek, które trzeba pisać do systemu plików może chcesz przekonwertować odebranych plików systemu adres URL lokalizacji rzeczywistych plików. Istnieje wiele sposobów robi to, w zależności od macierzystego platformy. + +Ważne jest, aby pamiętać, że nie wszystkie `cdvfile://` adresy URL są można zmapować na prawdziwe pliki w urządzeniu. Niektóre adresy URL może odnosić się do aktywów na urządzeniu, które nie są reprezentowane przez pliki, lub nawet może odnosić się do zasobów zdalnych. Ze względu na te możliwości wtyczki należy zawsze sprawdzić, czy się znaczącego wyniku powrót podczas próby konwersji adresów URL do ścieżki. + +#### Androida + +Na Android, najprostsza metoda konwersji `cdvfile://` URL do ścieżki systemu plików jest użycie `org.apache.cordova.CordovaResourceApi` . `CordovaResourceApi`jest kilka metod, które mogą obsługiwać `cdvfile://` adresów URL: + + Widok sieci Web jest członkiem Plugin klasy CordovaResourceApi resourceApi = webView.getResourceApi(); + + Uzyskać URL file:/// reprezentujących ten plik na urządzeniu / / lub ten sam adres URL niezmienione, jeśli nie mogą być mapowane do pliku fileURL Uri = resourceApi.remapUri(Uri.parse(cdvfileURL)); + + +Jest również możliwe, aby korzystać z wtyczki pliku bezpośrednio: + + org.apache.cordova.file.FileUtils przywóz; + org.apache.cordova.file.FileSystem przywóz; + java.net.MalformedURLException przywóz; + + Uzyskać pliku plugin manager wtyczki FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + Biorąc pod uwagę adres URL, uzyskać ścieżkę dla to spróbuj {String ścieżka = filePlugin.filesystemPathForURL(cdvfileURL);} catch (MalformedURLException e) {/ / url plików nie było uznane} + + +Do przeliczenia ścieżki do `cdvfile://` URL: + + org.apache.cordova.file.LocalFilesystemURL przywóz; + + Uzyskanie obiektu LocalFilesystemURL na ścieżkę urządzenia / / lub null, jeśli nie może być reprezentowana jako adres URL cdvfile. + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path); + Dostać reprezentację ciąg adresu URL obiektu String cdvfileURL = url.toString(); + + +Jeśli twój plugin tworzy plik, i chcesz zwraca obiekt FileEntry dla niego, użyj pliku plugin: + + Zwraca JSON struktura nadaje się do powrotu do JavaScript, / / lub null, jeśli ten plik nie jest reprezentować jako adres URL cdvfile. + Wpis JSONObject = filePlugin.getEntryForFile(file); + + +#### iOS + +Cordova na iOS nie korzystać z tego samego `CordovaResourceApi` koncepcji jak Android. Na iOS należy użyć pliku plugin do konwersji między adresach URL i ścieżkach plików. + + Uzyskać obiekt CDVFilesystem URL URL url ciąg CDVFilesystemURL * = [CDVFilesystemURL fileSystemURLWithString:cdvfileURL]; + Uzyskać ścieżkę dla URL obiektu, stawka zerowa, jeśli nie mogą być mapowane do ścieżki pliku NSString * = [filePlugin filesystemPathForURL:url]; + + + Dostać CDVFilesystem URL obiektu na ścieżkę urządzenia lub / / zerowe, jeśli nie może być reprezentowana jako adres URL cdvfile. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + Dostać reprezentację ciąg adresu URL obiektu NSString * cdvfileURL = [url absoluteString]; + + +Jeśli twój plugin tworzy plik, i chcesz zwraca obiekt FileEntry dla niego, użyj pliku plugin: + + Dostać CDVFilesystem URL obiektu na ścieżkę urządzenia lub / / zerowe, jeśli nie może być reprezentowana jako adres URL cdvfile. + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + Struktura wrócić do JavaScript NSDictionary * wpis = [filePlugin makeEntryForLocalURL:url] + + +#### JavaScript + +W JavaScript, aby uzyskać `cdvfile://` adres URL z obiektu FileEntry lub DirectoryEntry, wystarczy zadzwonić `.toURL()` na to: + + var cdvfileURL = entry.toURL(); + + +W plugin reakcji obsługi przerobić od zwróconych struktury FileEntry do rzeczywistego obiektu wejścia, kod obsługi należy zaimportować pliku plugin i utworzyć nowy obiekt: + + utworzyć odpowiedni wpis obiektu var wpis; + Jeśli (entryStruct.isDirectory) {wpis = nowy DirectoryEntry (entryStruct.name, entryStruct.fullPath, nowe FileSystem(entryStruct.filesystemName));} jeszcze {wpis = nowy FileEntry (entryStruct.name, entryStruct.fullPath, nowe FileSystem(entryStruct.filesystemName));} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/plugins.md b/mobile/plugins/cordova-plugin-file/doc/plugins.md new file mode 100644 index 0000000..a3329d6 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/plugins.md @@ -0,0 +1,120 @@ + + +Notes for plugin developers +=========================== + +These notes are primarily intended for Android and iOS developers who want to write plugins which interface with the file system using the File plugin. + +Working with Cordova file system URLs +------------------------------------- + +Since version 1.0.0, this plugin has used URLs with a `cdvfile` scheme for all communication over the bridge, rather than exposing raw device file system paths to JavaScript. + +On the JavaScript side, this means that FileEntry and DirectoryEntry objects have a fullPath attribute which is relative to the root of the HTML file system. If your plugin's JavaScript API accepts a FileEntry or DirectoryEntry object, you should call `.toURL()` on that object before passing it across the bridge to native code. + +### Converting cdvfile:// URLs to fileystem paths + +Plugins which need to write to the filesystem may want to convert a received file system URL to an actual filesystem location. There are multiple ways of doing this, depending on the native platform. + +It is important to remember that not all `cdvfile://` URLs are mappable to real files on the device. Some URLs can refer to assets on device which are not represented by files, or can even refer to remote resources. Because of these possibilities, plugins should always test whether they get a meaningful result back when trying to convert URLs to paths. + +#### Android + +On Android, the simplest method to convert a `cdvfile://` URL to a filesystem path is to use `org.apache.cordova.CordovaResourceApi`. `CordovaResourceApi` has several methods which can handle `cdvfile://` URLs: + + // webView is a member of the Plugin class + CordovaResourceApi resourceApi = webView.getResourceApi(); + + // Obtain a file:/// URL representing this file on the device, + // or the same URL unchanged if it cannot be mapped to a file + Uri fileURL = resourceApi.remapUri(Uri.parse(cdvfileURL)); + +It is also possible to use the File plugin directly: + + import org.apache.cordova.file.FileUtils; + import org.apache.cordova.file.FileSystem; + import java.net.MalformedURLException; + + // Get the File plugin from the plugin manager + FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + // Given a URL, get a path for it + try { + String path = filePlugin.filesystemPathForURL(cdvfileURL); + } catch (MalformedURLException e) { + // The filesystem url wasn't recognized + } + +To convert from a path to a `cdvfile://` URL: + + import org.apache.cordova.file.LocalFilesystemURL; + + // Get a LocalFilesystemURL object for a device path, + // or null if it cannot be represented as a cdvfile URL. + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path); + // Get the string representation of the URL object + String cdvfileURL = url.toString(); + +If your plugin creates a file, and you want to return a FileEntry object for it, use the File plugin: + + // Return a JSON structure suitable for returning to JavaScript, + // or null if this file is not representable as a cdvfile URL. + JSONObject entry = filePlugin.getEntryForFile(file); + +#### iOS + +Cordova on iOS does not use the same `CordovaResourceApi` concept as Android. On iOS, you should use the File plugin to convert between URLs and filesystem paths. + + // Get a CDVFilesystem URL object from a URL string + CDVFilesystemURL* url = [CDVFilesystemURL fileSystemURLWithString:cdvfileURL]; + // Get a path for the URL object, or nil if it cannot be mapped to a file + NSString* path = [filePlugin filesystemPathForURL:url]; + + + // Get a CDVFilesystem URL object for a device path, or + // nil if it cannot be represented as a cdvfile URL. + CDVFilesystemURL* url = [filePlugin fileSystemURLforLocalPath:path]; + // Get the string representation of the URL object + NSString* cdvfileURL = [url absoluteString]; + +If your plugin creates a file, and you want to return a FileEntry object for it, use the File plugin: + + // Get a CDVFilesystem URL object for a device path, or + // nil if it cannot be represented as a cdvfile URL. + CDVFilesystemURL* url = [filePlugin fileSystemURLforLocalPath:path]; + // Get a structure to return to JavaScript + NSDictionary* entry = [filePlugin makeEntryForLocalURL:url] + +#### JavaScript + +In JavaScript, to get a `cdvfile://` URL from a FileEntry or DirectoryEntry object, simply call `.toURL()` on it: + + var cdvfileURL = entry.toURL(); + +In plugin response handlers, to convert from a returned FileEntry structure to an actual Entry object, your handler code should import the File plugin and create a new object: + + // create appropriate Entry object + var entry; + if (entryStruct.isDirectory) { + entry = new DirectoryEntry(entryStruct.name, entryStruct.fullPath, new FileSystem(entryStruct.filesystemName)); + } else { + entry = new FileEntry(entryStruct.name, entryStruct.fullPath, new FileSystem(entryStruct.filesystemName)); + } + diff --git a/mobile/plugins/cordova-plugin-file/doc/ru/index.md b/mobile/plugins/cordova-plugin-file/doc/ru/index.md new file mode 100644 index 0000000..3c9fca9 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/ru/index.md @@ -0,0 +1,275 @@ + + +# cordova-plugin-file + +Этот плагин реализует API файла, позволяя доступ на чтение и запись в файлы, находящиеся на устройстве. + +Этот плагин основан на нескольких спецификации, в том числе: HTML5 API файла + +(Ныне несуществующей) каталоги и систему расширений Последнее: , хотя большая часть кода, плагин был написан, когда ранее спец был текущим: + +Он также реализует уничтожал spec: + +Для использования, пожалуйста, обратитесь к HTML5 скалы отличные [файловой системы статьи.][1] + + [1]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +Обзор других вариантов хранения найти Cordova [хранения руководства][2]. + + [2]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +## Установка + + cordova plugin add cordova-plugin-file + + +## Поддерживаемые платформы + +* Amazon Fire OS +* Android +* BlackBerry 10 +* Firefox OS +* iOS +* Windows Phone 7 и 8 * +* Windows 8 * + +* *Эти платформы не поддерживают `FileReader.readAsArrayBuffer` , ни `FileWriter.write(blob)` .* + +## Где хранить файлы + +По состоянию на v1.2.0 приведены URL-адреса для важных файлов в системные каталоги. Каждый URL-адрес в виде *file:///path/to/spot/*и может быть преобразован в `DirectoryEntry` с помощью`window.resolveLocalFileSystemURL()`. + +* `cordova.file.applicationDirectory`-Каталог только для чтения, где установлено приложение. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.applicationStorageDirectory`-Корневой каталог приложения в песочнице; на iOS это место только для чтения (но определенных подкаталогов [как `/Documents` ], чтения записи). Все данные, содержащиеся в частных в приложение. ( *iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.dataDirectory`-Хранения стойкие и частных данных в приложения в песочнице с использованием внутренней памяти (на Android, если необходимо использовать внешнюю память, использовать `.externalDataDirectory` ). На iOS, этот каталог не синхронизируется с iCloud (использование `.syncedDataDirectory` ). (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.cacheDirectory`-Каталог для кэшированных данных файлов или все файлы, которые ваше приложение может повторно создать легко. ОС может удалить эти файлы, когда устройства хватает на хранение, тем не менее, приложения не должны опираться на OS, чтобы удалить файлы здесь. (*iOS*, *Android*, *BlackBerry 10*) + +* `cordova.file.externalApplicationStorageDirectory`-Пространство приложения на внешнем хранилище. (*Android*) + +* `cordova.file.externalDataDirectory`-Куда положить файлы данных конкретного приложения на внешнем хранилище. (*Android*) + +* `cordova.file.externalCacheDirectory`-Применение кэш на внешние накопители. (*Android*) + +* `cordova.file.externalRootDirectory`-Корень внешние накопители (SD карта). (*Android*, *BlackBerry 10*) + +* `cordova.file.tempDirectory`-Временный каталог, что ОС можно снять на будет. Не следует полагаться на OS, чтобы очистить этот каталог; Ваше приложение всегда следует удалять файлы в соответствующих случаях. (*iOS*) + +* `cordova.file.syncedDataDirectory`-Содержит файлы приложения, которые должны быть синхронизированы (например, к iCloud). (*iOS*) + +* `cordova.file.documentsDirectory`-Файлы для приложения, но это являются значимыми для других приложений (например, файлы Office). (*iOS*) + +* `cordova.file.sharedDirectory`-Файлы глобально доступной для всех приложений (*BlackBerry 10*) + +## Макеты файловой системы + +Хотя технически деталь реализации, она может быть очень полезно знать как `cordova.file.*` карта свойства физические пути на реальном устройстве. + +### iOS расположения файловой системы + +| Путь к устройству | `Cordova.File.*` | `iosExtraFileSystems` | r/w? | стойкие? | Очищает ОС | Синхронизация | частные | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:----:|:--------:|:----------:|:-------------:|:-------:| +| `/ var/мобильного/применения/< UUID > /` | applicationStorageDirectory | - | r | Н/Д | Н/Д | Н/Д | Да | +|    `appname.app/` | applicationDirectory | расслоение | r | Н/Д | Н/Д | Н/Д | Да | +|       `www/` | - | - | r | Н/Д | Н/Д | Н/Д | Да | +|    `Documents/` | documentsDirectory | документы | r/w | Да | Нет | Да | Да | +|       `NoCloud/` | - | документы nosync | r/w | Да | Нет | Нет | Да | +|    `Library` | - | Библиотека | r/w | Да | Нет | Да? | Да | +|       `NoCloud/` | dataDirectory | Библиотека nosync | r/w | Да | Нет | Нет | Да | +|       `Cloud/` | syncedDataDirectory | - | r/w | Да | Нет | Да | Да | +|       `Caches/` | cacheDirectory | кэш | r/w | Да * | Да * * *| | Нет | Да | +|    `tmp/` | tempDirectory | - | r/w | Не * * | Да * * *| | Нет | Да | + +* Файлы сохраняются приложения перезагрузки и обновления, но этот каталог может быть очищен, когда ОС желаний. Ваше приложение должно иметь возможность воссоздать любое содержание, которое может быть удалено. + +* * Файлы могут сохраняться перезагрузками app, но не полагайтесь на это поведение. Для продолжения обновления файлов не гарантируется. Приложение должно удалить файлы из этого каталога, когда это применимо, как операционная система не гарантирует когда (или даже если) эти файлы будут удалены. + +* * *| ОС может очистить содержимое этого каталога, когда он считает это необходимым, но не полагайтесь на это. Необходимо снять этот каталог в зависимости от вашего приложения. + +### Расположения Android файловой системы + +| Путь к устройству | `Cordova.File.*` | `AndroidExtraFileSystems` | r/w? | стойкие? | Очищает ОС | частные | +|:--------------------------------- |:----------------------------------- |:------------------------- |:----:|:--------:|:----------:|:-------:| +| `File:///android_asset/` | applicationDirectory | | r | Н/Д | Н/Д | Да | +| `/ Data/data/< app-id > /` | applicationStorageDirectory | - | r/w | Н/Д | Н/Д | Да | +|    `cache` | cacheDirectory | кэш | r/w | Да | Да * | Да | +|    `files` | dataDirectory | файлы | r/w | Да | Нет | Да | +|       `Documents` | | документы | r/w | Да | Нет | Да | +| `< sdcard > /` | externalRootDirectory | SDCard | r/w | Да | Нет | Нет | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | Да | Нет | Нет | +|       `cache` | externalCacheDirectry | кэш внешние | r/w | Да | Не * * | Нет | +|       `files` | externalDataDirectory | файлы внешние | r/w | Да | Нет | Нет | + +* ОС может периодически удалять этот каталог, но не полагайтесь на это поведение. Очистите содержимое этого каталога в зависимости от вашего приложения. Если пользователь вручную очистить кэш, содержимое этого каталога будут удалены. + +* * ОС не ясно этот каталог автоматически; Вы несете ответственность за управление содержимым самостоятельно. Если пользователь вручную очистить кэш, содержимое каталога будут удалены. + +**Примечание**: Если нельзя монтировать внешние накопители, `cordova.file.external*` Свойства`null`. + +### BlackBerry 10 расположения файловой системы + +| Путь к устройству | `Cordova.File.*` | r/w? | стойкие? | Очищает ОС | частные | +|:--------------------------------------------------- |:--------------------------- |:----:|:--------:|:----------:|:-------:| +| `File:///Accounts/1000/AppData/ < app id > /` | applicationStorageDirectory | r | Н/Д | Н/Д | Да | +|    `app/native` | applicationDirectory | r | Н/Д | Н/Д | Да | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | Нет | Да | Да | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | Да | Нет | Да | +| `File:///Accounts/1000/Removable/SDCard` | externalRemovableDirectory | r/w | Да | Нет | Нет | +| `File:///Accounts/1000/Shared` | sharedDirectory | r/w | Да | Нет | Нет | + +*Примечание*: при развертывании приложения для работы периметра, все пути относительны /accounts/1000-enterprise. + +## Особенности Android + +### Местоположение Android постоянного хранения + +Есть несколько допустимых мест для хранения постоянных файлов на устройстве Android. Смотрите [эту страницу][3] для широкого обсуждения различных возможностей. + + [3]: http://developer.android.com/guide/topics/data/data-storage.html + +Предыдущие версии плагина будет выбирать расположение временных и постоянных файлов при запуске, основанный на ли устройство утверждал, что SD-карта (или эквивалентные хранения раздел) был смонтирован. Если была смонтирована SD-карты, или если большой внутренней памяти раздел был доступен (такие как на устройствах Nexus,), то постоянные файлы будут храниться в корне этого пространства. Это означало, что все apps Cordova могли видеть все файлы, имеющиеся на карте. + +Если SD-карты не был доступен, то предыдущих версий будет хранить данные в `/data/data/` , которая изолирует приложения друг от друга, но все еще может причина данные распределяются между пользователями. + +Это теперь можно выбрать, следует ли хранить файлы в месте хранения внутренних файлов, или с использованием предыдущей логики, с предпочтением в вашем приложении `config.xml` файл. Чтобы сделать это, добавить один из этих двух линий в `config.xml` : + + + + + + +Без этой линии, будет использовать файл плагина `Compatibility` по умолчанию. Если тег предпочтений присутствует и не является одним из этих значений, приложение не запустится. + +Если ранее была отгружена приложения для пользователей, используя старые (до 1.0) версию этого плагина и имеет сохраненные файлы в файловой системе постоянных, то вы должны установить предпочтения `Compatibility` . Переключение местоположение для «Внутреннего» будет означать, что существующие пользователи, которые обновить их применение может быть не в состоянии получить доступ к их сохраненные ранее файлы, в зависимости от их устройства. + +Если ваше приложение является новым или ранее никогда не хранит файлы в стойких файловой системы, то `Internal` как правило рекомендуется настройка. + +## Особенности iOS + +* `cordova.file.applicationStorageDirectory`доступен только для чтения; попытка хранения файлов в корневом каталоге не удастся. Использовать один из других `cordova.file.*` свойства, определенные для iOS (только `applicationDirectory` и `applicationStorageDirectory` доступны только для чтения). +* `FileReader.readAsText(blob, encoding)` + * `encoding`Параметр не поддерживается, и UTF-8 кодирование действует всегда. + +### iOS место постоянного хранения + +Существует два допустимых местоположений для хранения постоянных файлов на устройства iOS: документы каталогов и библиотека. Предыдущие версии плагина только когда-либо постоянные файлы хранятся в папке документы. Это был побочный эффект делает все файлы приложения в iTunes, который часто был непреднамеренным, особенно для приложений, которые обрабатывают большое количество мелких файлов, вместо того, чтобы производить полный комплект документов для экспорта, который является цель каталога. + +Это теперь можно выбрать, следует ли хранить файлы в документы или каталоге библиотеки, с предпочтением в вашем приложении `config.xml` файл. Чтобы сделать это, добавить один из этих двух линий в `config.xml` : + + + + + + +Без этой линии, будет использовать файл плагина `Compatibility` по умолчанию. Если тег предпочтений присутствует и не является одним из этих значений, приложение не запустится. + +Если ранее была отгружена приложения для пользователей, используя старые (до 1.0) версию этого плагина и имеет сохраненные файлы в файловой системе постоянных, то вы должны установить предпочтения `Compatibility` . Переключение расположения `Library` будет означать, что существующих пользователей обновить их применения будет не в состоянии получить доступ к их сохраненные ранее файлы. + +Если ваше приложение является новым или ранее никогда не хранит файлы в стойких файловой системы, то `Library` как правило рекомендуется настройка. + +## Особенности Firefox OS + +API файловой системы изначально не поддерживается Firefox OS и реализуется как оболочка поверх indexedDB. + +* Не вынимая непустые каталоги +* Не поддерживает метаданные для каталогов +* Методы `copyTo` и `moveTo` не поддерживает каталоги + +Поддерживаются следующие пути данных: * `applicationDirectory` -использует `xhr` чтобы получить локальные файлы, которые упакованы с приложением. * `dataDirectory` - Для постоянных данных конкретного приложения файлов. * `cacheDirectory` -Кэшированных файлов, которые должны выжить перезагрузки приложения (Apps не следует полагаться на OS, чтобы удалить файлы из здесь). + +## Обновление примечания + +В v1.0.0 этого плагина `FileEntry` и `DirectoryEntry` структур изменились, более соответствует опубликованной спецификации. + +Предыдущий (pre-1.0.0) версии плагина хранятся устройства Абсолют файл расположение в `fullPath` свойства `Entry` объектов. Эти пути обычно будет выглядеть + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +Эти пути также были возвращены `toURL()` метода `Entry` объектов. + +С v1.0.0 `fullPath` атрибут является путь к файлу, *заданный относительно корня файловой системы HTML*. Таким образом, выше пути будет теперь оба быть представлено `FileEntry` объект с `fullPath` из + + /path/to/file + + +Если ваше приложение работает с устройства Абсолют путями, и ранее были получены эти пути через `fullPath` свойства `Entry` объектов, то вам следует обновить код для использования `entry.toURL()` вместо этого. + +Для обратной совместимости, `resolveLocalFileSystemURL()` метод будет принимать путь Абсолют устройства и будет возвращать `Entry` объект, соответствующий его, до тех пор, как этот файл существует в рамках либо `TEMPORARY` или `PERSISTENT` файловых систем. + +Это особенно была проблема с плагином передачи файлов, который ранее использовался устройства Абсолют пути (и все еще может принять их). Он был обновлен для корректной работы с файловой системы URL, так что замена `entry.fullPath` с `entry.toURL()` должен решить любые вопросы, получить этот плагин для работы с файлами на устройстве. + +В v1.1.0 возвращаемое значение из `toURL()` был изменен (см. \[CB-6394\] (https://issues.apache.org/jira/browse/CB-6394)) для возвращения URL-адрес абсолютным «file://». где это возможно. Для обеспечения ' cdvfile:'-вы можете использовать URL-адрес `toInternalURL()` сейчас. Этот метод будет возвращать теперь файловой системы URL формы + + cdvfile://localhost/persistent/path/to/file + + +который может использоваться для уникальной идентификации файла. + +## Список кодов ошибок и значения + +Когда возникает ошибка, один из следующих кодов будет использоваться. + +| Код | Постоянная | +| ---:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## Настройка плагина (опционально) + +Набор доступных файловых систем может быть настроен на платформе. IOS и Android признают тег в `config.xml` имена которых файловые системы для установки. По умолчанию включены все корни файловой системы. + + + + + +### Android + +* `files`: Каталог для хранения внутреннего файла приложения +* `files-external`: Каталог хранения внешнего файла приложения +* `sdcard`: Глобальный внешний файл каталог хранения (это корень SD-карты, если таковая установлена). Вы должны иметь `android.permission.WRITE_EXTERNAL_STORAGE` разрешение использовать это. +* `cache`: Каталог внутреннего кэша приложения +* `cache-external`: Каталог приложения внешней кэш-памяти +* `root`: Все устройство файловой системы + +Android поддерживает также Специальный файловую систему под названием «документы», которая представляет подкаталог «/ документы /» в пределах файловой системы «файлы». + +### iOS + +* `library`: Каталог библиотеки приложения +* `documents`: Каталог документов приложения +* `cache`: Каталог кэша приложения +* `bundle`: Пакет приложения; расположение самого приложения на диске (только для чтения) +* `root`: Все устройство файловой системы + +По умолчанию каталоги библиотеки и документы можно синхронизировать с iCloud. Вы также можете заказать два дополнительных файловых систем, `library-nosync` и `documents-nosync` , которые представляют Специальный каталог не синхронизируются в `/Library` или `/Documents` файловой системы. diff --git a/mobile/plugins/cordova-plugin-file/doc/ru/plugins.md b/mobile/plugins/cordova-plugin-file/doc/ru/plugins.md new file mode 100644 index 0000000..2445d09 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/ru/plugins.md @@ -0,0 +1,124 @@ + + +# Примечания для разработчиков плагинов + +Эти примечания предназначены прежде всего для Android и iOS разработчиков, которые хотят писать плагины какой интерфейс с файловой системой, с помощью файла плагина. + +## Работа с Кордова файловой системы URL + +Начиная с версии 1.0.0, этот плагин использует URL-адресов с `cdvfile` схема для всех коммуникации через мост, а не подвергая пути файловой системы raw устройства для JavaScript. + +На стороне JavaScript это означает, что объекты DirectoryEntry и FileEntry fullPath атрибут, который является по отношению к корневой файловой системе HTML. Если ваш плагин JavaScript API принимает объект DirectoryEntry или FileEntry, необходимо вызвать `.toURL()` для этого объекта перед передачей их через мост в машинный код. + +### Преобразование cdvfile: / / URL-адреса в пути fileystem + +Плагины, которые нужно написать в файловой системе может потребоваться преобразовать URL-адреса системы полученный файл в место фактической файловой системы. Существует несколько способов сделать это, в зависимости от родной платформе. + +Важно помнить, что не все `cdvfile://` URL-адреса являются отображаемыми файлами на устройстве. Некоторые URL может относиться к активам на устройстве, которые не представлены файлы, или может даже обратиться к удаленным ресурсам. Из-за эти возможности плагины следует всегда проверять ли они получают результат обратно при попытке преобразовать URL-адреса в пути. + +#### Android + +На Android, самый простой способ для преобразования `cdvfile://` URL-адрес к пути файловой системы заключается в использовании `cordova-plugin-CordovaResourceApi` . `CordovaResourceApi`Есть несколько методов, которые можно обработать `cdvfile://` URL-адреса: + + // webView is a member of the Plugin class + CordovaResourceApi resourceApi = webView.getResourceApi(); + + // Obtain a file:/// URL representing this file on the device, + // or the same URL unchanged if it cannot be mapped to a file + Uri fileURL = resourceApi.remapUri(Uri.parse(cdvfileURL)); + + +Это также можно использовать плагин файл непосредственно: + + import cordova-plugin-file.FileUtils; + import cordova-plugin-file.FileSystem; + import java.net.MalformedURLException; + + // Get the File plugin from the plugin manager + FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + // Given a URL, get a path for it + try { + String path = filePlugin.filesystemPathForURL(cdvfileURL); + } catch (MalformedURLException e) { + // The filesystem url wasn't recognized + } + + +Для преобразования пути к `cdvfile://` URL-адрес: + + import cordova-plugin-file.LocalFilesystemURL; + + // Get a LocalFilesystemURL object for a device path, + // or null if it cannot be represented as a cdvfile URL. + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path); + // Get the string representation of the URL object + String cdvfileURL = url.toString(); + + +Если ваш плагин создает файл, и вы хотите вернуть объект FileEntry для него, используйте файл плагина: + + // Return a JSON structure suitable for returning to JavaScript, + // or null if this file is not representable as a cdvfile URL. + JSONObject entry = filePlugin.getEntryForFile(file); + + +#### iOS + +Кордова на iOS не использовать те же `CordovaResourceApi` понятие, как Android. На iOS вы должны использовать файл плагин для преобразования URL-адреса и пути файловой системы. + + // Get a CDVFilesystem URL object from a URL string + CDVFilesystemURL* url = [CDVFilesystemURL fileSystemURLWithString:cdvfileURL]; + // Get a path for the URL object, or nil if it cannot be mapped to a file + NSString* path = [filePlugin filesystemPathForURL:url]; + + + // Get a CDVFilesystem URL object for a device path, or + // nil if it cannot be represented as a cdvfile URL. + CDVFilesystemURL* url = [filePlugin fileSystemURLforLocalPath:path]; + // Get the string representation of the URL object + NSString* cdvfileURL = [url absoluteString]; + + +Если ваш плагин создает файл, и вы хотите вернуть объект FileEntry для него, используйте файл плагина: + + // Get a CDVFilesystem URL object for a device path, or + // nil if it cannot be represented as a cdvfile URL. + CDVFilesystemURL* url = [filePlugin fileSystemURLforLocalPath:path]; + // Get a structure to return to JavaScript + NSDictionary* entry = [filePlugin makeEntryForLocalURL:url] + + +#### JavaScript + +В JavaScript, чтобы получить `cdvfile://` URL от объекта DirectoryEntry или FileEntry, просто позвоните `.toURL()` на него: + + var cdvfileURL = entry.toURL(); + + +В плагин обработчики ответ для преобразования из возвращаемой структуры FileEntry объект фактического вступления, код обработчика следует импортировать файл плагина и создайте новый объект: + + // create appropriate Entry object + var entry; + if (entryStruct.isDirectory) { + entry = new DirectoryEntry(entryStruct.name, entryStruct.fullPath, new FileSystem(entryStruct.filesystemName)); + } else { + entry = new FileEntry(entryStruct.name, entryStruct.fullPath, new FileSystem(entryStruct.filesystemName)); + } diff --git a/mobile/plugins/cordova-plugin-file/doc/zh/README.md b/mobile/plugins/cordova-plugin-file/doc/zh/README.md new file mode 100644 index 0000000..c600587 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/zh/README.md @@ -0,0 +1,335 @@ + + +# cordova-plugin-file + +[![Build Status](https://travis-ci.org/apache/cordova-plugin-file.svg)](https://travis-ci.org/apache/cordova-plugin-file) + +這個外掛程式實現檔 API 允許對檔駐留在該設備上的讀/寫訪問。 + +這個外掛程式基於幾個規格,包括: HTML5 檔 API [HTTP://www.w3.org/TR/FileAPI/](http://www.w3.org/TR/FileAPI/) + +(現已解散) 目錄和系統擴展最新: [HTTP://www.w3.org/TR/2012/WD-file-system-api-20120417/](http://www.w3.org/TR/2012/WD-file-system-api-20120417/)雖然大部分的外掛程式代碼寫時較早的規格是當前: [HTTP://www.w3.org/TR/2011/WD-file-system-api-20110419/](http://www.w3.org/TR/2011/WD-file-system-api-20110419/) + +它還實現 FileWriter 規格: [HTTP://dev.w3.org/2009/dap/file-system/file-writer.html](http://dev.w3.org/2009/dap/file-system/file-writer.html) + +用法,請參閱對 HTML5 的岩石優秀[檔案系統文章。](http://www.html5rocks.com/en/tutorials/file/filesystem/) + +其他存儲選項的概述,請參閱科爾多瓦的[存儲指南](http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html). + +這個外掛程式定義全球 `cordova.file` 物件。 + +雖然在全球範圍內,它不可用直到 `deviceready` 事件之後。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## 安裝 + + cordova plugin add cordova-plugin-file + + +## 支援的平臺 + + * 亞馬遜火 OS + * Android 系統 + * 黑莓 10 + * 火狐瀏覽器作業系統 + * iOS + * Windows Phone 7 和 8 * + * Windows 8 * + * Windows* + * 瀏覽器 + +\* *These platforms do not support `FileReader.readAsArrayBuffer` nor `FileWriter.write(blob)`.* + +## 存儲檔的位置 + +截至 v1.2.0,提供重要的檔案系統目錄的 Url。 每個 URL 位於表單 *file:///path/to/spot/*,和可以轉換為使用 `window.resolveLocalFileSystemURL()` 的 `DirectoryEntry`. + + * `cordova.file.applicationDirectory`-唯讀目錄在哪裡安裝的應用程式。(*iOS*、*安卓*、*黑莓 10*) + + * `cordova.file.applicationStorageDirectory`-根目錄下的應用程式的沙箱 ;在 iOS 上此位置是唯讀 (但特定的子目錄 [像 `/Documents` ] 都是讀寫)。 中包含的所有資料都是私有的應用程式。 ( *iOS*、*安卓*、*黑莓 10*) + + * `cordova.file.dataDirectory`資料持久性和私有資料存儲在內部記憶體使用的應用程式的沙箱內 (在安卓系統,如果你需要使用外部儲存體,使用 `.externalDataDirectory` )。 在 iOS,此目錄不與 iCloud 同步 (使用 `.syncedDataDirectory` )。 (*iOS*、*安卓*、*黑莓 10*) + + * `cordova.file.cacheDirectory`-緩存的資料檔案或您的應用程式重新可以輕鬆地創建的任何檔的目錄。 作業系統可能會刪除這些檔,該設備在存儲上運行低時,然而,應用程式不應依賴的作業系統,請刪除檔在這裡。 (*iOS*、*安卓*、*黑莓 10*) + + * `cordova.file.externalApplicationStorageDirectory`-應用程式外部存儲上的空間。(*安卓*) + + * `cordova.file.externalDataDirectory`-放在外部存儲特定于應用程式的資料檔案的位置。(*安卓*) + + * `cordova.file.externalCacheDirectory`-在外部存儲應用程式緩存。(*安卓*) + + * `cordova.file.externalRootDirectory`-外部存儲 (SD 卡) 的根。(*安卓*、*黑莓 10*) + + * `cordova.file.tempDirectory`-OS 可以清除時的空目錄會。 不依賴于 OS,以清除此目錄 ;您的應用程式,應總是移除作為適用的檔。 (*iOS*) + + * `cordova.file.syncedDataDirectory`-保存應同步 (例如到 iCloud) 的特定于應用程式的檔。(*iOS*) + + * `cordova.file.documentsDirectory`-檔私有的應用程式,但這是對其他應用程式 (例如 Office 檔) 有意義。(*iOS*) + + * `cordova.file.sharedDirectory`-對所有應用程式 (*黑莓 10*全域可用的檔) + +## 檔案系統佈局 + +雖然技術上實現的細節,它可以是很有必要瞭解如何 `cordova.file.*` 屬性對應到實體路徑在實際設備上。 + +### iOS 檔案系統佈局 + +| 設備路徑 | `cordova.file.*` | `iosExtraFileSystems` | r/w 嗎? | 持續性嗎? | OS 清除 | 同步 | 私人 | +|:---------------------------------------------- |:--------------------------- |:--------------------- |:------:|:-------:|:------------:|:---:|:--:| +| `/ 無功/移動/應用程式/< UUID > /` | applicationStorageDirectory | - | r | 不適用 | 不適用 | 不適用 | 是啊 | +|    `appname.app/` | applicationDirectory | 束 | r | 不適用 | 不適用 | 不適用 | 是啊 | +|       `www/` | - | - | r | 不適用 | 不適用 | 不適用 | 是啊 | +|    `Documents/` | documentsDirectory | 檔 | r/w | 是啊 | 無 | 是啊 | 是啊 | +|       `NoCloud/` | - | 檔 nosync | r/w | 是啊 | 無 | 無 | 是啊 | +|    `Library` | - | 圖書館 | r/w | 是啊 | 無 | 是嗎? | 是啊 | +|       `NoCloud/` | dataDirectory | 圖書館 nosync | r/w | 是啊 | 無 | 無 | 是啊 | +|       `Cloud/` | syncedDataDirectory | - | r/w | 是啊 | 無 | 是啊 | 是啊 | +|       `Caches/` | cacheDirectory | 快取記憶體 | r/w | 是啊 * | 是啊**\* | 無 | 是啊 | +|    `tmp/` | tempDirectory | - | r/w | 無** | 是啊**\* | 無 | 是啊 | + +\ * 檔堅持跨應用程式重新開機和升級,但每當 OS 的欲望,可以清除此目錄。您的應用程式應該能夠重新創建任何內容可能會被刪除。 + +**檔可能會持續整個應用程式重新開機,但不是依賴于這種行為。 不保證檔在更新之間持續存在。 您的應用程式時適用,是應該刪除此目錄的檔,因為作業系統並不能保證何時 (或即使) 中刪除這些檔。 + +**\ * 作業系統可能會清除此目錄的內容,每當它感覺它是必要的但做不依賴于此。 你應該清除此目錄為適合您的應用程式。 + +### Android 的檔案系統佈局 + +| 設備路徑 | `cordova.file.*` | `AndroidExtraFileSystems` | r/w 嗎? | 持續性嗎? | OS 清除 | 私人 | +|:------------------------------------------------ |:----------------------------------- |:------------------------- |:------:|:-----:|:-------:|:--:| +| `file:///android_asset/` | applicationDirectory | | r | 不適用 | 不適用 | 是啊 | +| `/ 資料資料/< 應用程式 id > /` | applicationStorageDirectory | - | r/w | 不適用 | 不適用 | 是啊 | +|    `cache` | cacheDirectory | 快取記憶體 | r/w | 是啊 | 是啊\* | 是啊 | +|    `files` | dataDirectory | 檔 | r/w | 是啊 | 無 | 是啊 | +|       `Documents` | | 檔 | r/w | 是啊 | 無 | 是啊 | +| `< sd 卡 > /` | externalRootDirectory | sd 卡 | r/w | 是啊 | 無 | 無 | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | 是啊 | 無 | 無 | +|       `cache` | externalCacheDirectry | 外部快取記憶體 | r/w | 是啊 | 無** | 無 | +|       `files` | externalDataDirectory | 外部檔 | r/w | 是啊 | 無 | 無 | + +\ * 作業系統可能定期清除此目錄,但不是依賴于這種行為。 清除此為適合您的應用程式的目錄的內容。 使用者應手動清除緩存,將刪除此目錄的內容。 + +** OS 不會清除此目錄自動;你是負責管理自己的內容。 使用者應手動清除緩存,目錄中的內容將被刪除。 + +**注**: 如果外部存儲無法裝入,`cordova.file.external*` 屬性為 `空`. + +### 黑莓 10 檔案系統佈局 + +| 設備路徑 | `cordova.file.*` | r/w 嗎? | 持續性嗎? | OS 清除 | 私人 | +|:----------------------------------------------------------- |:--------------------------- |:------:|:-----:|:-----:|:--:| +| `file:///accounts/1000/appdata/ < 應用程式 id > /` | applicationStorageDirectory | r | 不適用 | 不適用 | 是啊 | +|    `app/native` | applicationDirectory | r | 不適用 | 不適用 | 是啊 | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | 無 | 是啊 | 是啊 | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | 是啊 | 無 | 是啊 | +| `file:///accounts/1000/removable/sdcard` | externalRemovableDirectory | r/w | 是啊 | 無 | 無 | +| `file:///accounts/1000/shared` | sharedDirectory | r/w | 是啊 | 無 | 無 | + +*注意*: 當應用程式部署工作週邊時,所有路徑都是相對於 /accounts/1000-enterprise。 + +## Android 的怪癖 + +### Android 的持久性存儲位置 + +有很多有效的位置來存儲持久性檔在 Android 設備上。 請參閱 [此頁面](http://developer.android.com/guide/topics/data/data-storage.html) 的各種可能性進行廣泛討論。 + +以前版本的外掛程式會選擇在啟動時,基於該設備是否聲稱 SD 卡 (或等效存儲分區) 展開,臨時和永久檔的位置。 如果被掛載 SD 卡,或一個大的內部存儲分區可用 (如 nexus 系列設備上) 然後持久性檔將存儲在該空間的根目錄中。 這意味著所有的科爾多瓦應用程式可以看到所有可用的檔在卡片上。 + +如果 SD 卡不是可用的那麼以前的版本中將存儲資料下的 `/data/data/`,其中隔離應用程式從彼此,但仍可能導致使用者之間共用的資料。 + +現在可以選擇是否將檔存儲在內部檔的存儲位置,或使用以前的邏輯,與您的應用程式的 `config.xml` 檔中的偏好。 要執行此操作,請將以下兩行之一添加到 `config.xml`: + + + + + + +如果這條線,沒有檔外掛程式將使用 `Compatibility` 作為預設值。如果首選項標記存在,並不是這些值之一,應用程式將無法啟動。 + +如果您的應用程式以前已被運到使用者,使用較舊的 (預 1.0) 版本的這個外掛程式,並具有持久性的檔,系統中存儲的檔,然後您應該設置 `Compatibility` 偏好。 切換到"Internal"的位置,將意味著現有使用者升級他們的應用程式可能無法訪問他們以前存儲的檔,具體取決於他們的設備。 + +如果您的應用程式是新的或以前從未有持久性的檔案系統中存儲檔,那麼通常建議使用 `Internal` 設置。 + +### 緩慢的遞迴操作為 /android_asset 的 + +上市資產目錄是在 android 系統很慢的。 你可以讓時間加速了不過,通過將`src/android/build-extras.gradle`添加到您的 android 專案的根 (也需要 cordova-android@4.0.0 或更高版本)。 + +## iOS 的怪癖 + + * `cordova.file.applicationStorageDirectory`是唯讀的 ;試圖存儲內的根目錄中的檔將會失敗。 使用的另一個 `cordova.file.*` 為 iOS 定義的屬性 (只有 `applicationDirectory` 和 `applicationStorageDirectory` 都是唯讀)。 + * `FileReader.readAsText(blob, encoding)` + * `encoding`參數不受支援,而 utf-8 編碼總是效果。 + +### iOS 的持久性存儲位置 + +有兩個有效的位置來存儲持久性在 iOS 設備上的檔: 檔目錄和圖書館目錄。 以前版本的外掛程式永遠只能將持久性檔存儲在文檔目錄中。 這已經使所有應用程式檔可見在 iTunes,往往是無意為之,尤其是對於處理大量小檔的應用程式中,而不是生產供出口,該目錄的既定的目標是證件齊全的副作用。 + +現在可以選擇是否將檔存儲在檔或庫目錄,與您的應用程式的 `config.xml` 檔中的偏好。 要執行此操作,請將以下兩行之一添加到 `config.xml`: + + + + + + +如果這條線,沒有檔外掛程式將使用 `Compatibility` 作為預設值。如果首選項標記存在,並不是這些值之一,應用程式將無法啟動。 + +如果您的應用程式以前已被運到使用者,使用較舊的 (預 1.0) 版本的這個外掛程式,並具有持久性的檔,系統中存儲的檔,然後您應該設置 `Compatibility` 偏好。 切換到 `Library` 的位置,將意味著現有使用者升級他們的應用程式將無法訪問他們以前存儲的檔。 + +如果您的應用程式是新的或以前從未有持久性的檔案系統中存儲檔,那麼通常建議使用 `Internal` 設置。 + +## 火狐瀏覽器作業系統的怪癖 + +檔案系統 API 本身不支援火狐瀏覽器的作業系統,作為墊片在 indexedDB 上實現的。 + + * 不會失敗時刪除非空的目錄 + * 不支援中繼資料的目錄 + * 方法 `copyTo` 和 `moveTo` 不支援目錄 + +支援以下資料路徑: * `applicationDirectory`-使用 `xhr` 獲取與應用程式打包的本地檔。 `dataDirectory`-用於持久性的特定于應用程式的資料檔案。 `cacheDirectory`-生存應重新開機應用程式的快取檔案 (應用程式不應依賴作業系統來刪除檔在這裡)。 + +## 瀏覽器的怪癖 + +### 常見的怪癖和備註 + + * 每個瀏覽器使用其自己的沙箱檔案系統。IE 和火狐瀏覽器使用 IndexedDB 作為一個基地。所有瀏覽器都使用正斜杠作為路徑中的目錄分隔符號。 + * 目錄條目不得不先後創建。 例如,調用 `fs.root.getDirectory (' dir1/dir2 ',{create:true},successCallback,errorCallback)`,如果不存在 dir1 將失敗。 + * 外掛程式將請求使用者許可權,以便在應用程式初次開機使用持久性存儲。 + * 外掛程式支援 `cdvfile://localhost` (本地資源) 只。通過 `cdvfile` 不支援外部資源即. + * 該外掛程式不遵循 ["檔案系統 API 8.3 命名限制"](http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions). + * Blob 和檔 ' `close` 功能不受支援。 + * `FileSaver` 和 `BlobBuilder` 不支援這個外掛程式,沒有存根 (stub)。 + * 該外掛程式不支援 `requestAllFileSystems`。這個功能也是缺少規範中。 + * 在目錄中的條目將不會被刪除,如果您使用 `create: true` 標誌為現有目錄。 + * 不支援通過建構函式創建的檔。你應該使用 entry.file 方法。 + * 每個瀏覽器使用它自己的形式為 blob 的 URL 引用。 + * 支援 `readAsDataURL` 功能,但在 Chrome 中的媒體類型取決於輸入副檔名,在 IE 中的媒體類型都始終空著 (這是 `純文字` 按照說明書一樣),在 Firefox 中的媒體類型始終是 `應用程式/八位位元組流`。 例如,如果內容是 `abcdefg` 然後火狐瀏覽器返回 `資料: 應用程式 / 八位位元組流 ; base64,YWJjZGVmZw = =`,即返回 `資料: ; base64,YWJjZGVmZw = =`,鉻返回 `資料: < 媒體類型根據擴展條目名稱 > ; base64,YWJjZGVmZw = =`. + * 在表單 `file:///persistent/path/to/entry` 火狐瀏覽器 IE),`toInternalURL` 返回的路徑。 鉻在表單 `cdvfile://localhost/persistent/file` 返回的路徑. + +### 鉻的怪癖 + + * 設備準備好事件之後,chrome 檔案系統並不能立即準備。作為一種變通方法,您可以訂閱到 `filePluginIsReady` 事件。示例: + +```javascript +window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); +``` + +你可以使用 `window.isFilePluginReadyRaised` 函數來檢查是否已經引發了事件。 -window.requestFileSystem 臨時和永久性檔案系統配額並不局限于鉻。 為增加中鉻的持久性存儲,您需要調用 `window.initPersistentFileSystem` 方法。 預設情況下,持久性存儲配額為 5 MB。 鉻需要 `— — 允許--訪問-從-檔` 通過 `file:///` 協定運行參數對 API 的支援。 -如果您使用標誌,將不更改 `檔` 物件 `{create:true}` 現有 `條目` 的時候。 -事件 `可取消` 屬性設置為 true 在 Chrome 中。 這是違反了 [規範](http://dev.w3.org/2009/dap/file-system/file-writer.html)。 -中鉻的 `toURL` 函數返回 `檔案系統:`-首碼路徑具體取決於應用程式主機。 例如,`filesystem:file:///persistent/somefile.txt`,`filesystem:HTTP://localhost:8080/persistent/somefile.txt`。 -`toURL` 函數結果不包含尾部反斜線在目錄條目的情況下。 鉻雖然正確解析目錄帶斜杠落後的 url。 -`resolveLocalFileSystemURL` 方法需要入站的 `url` 必須具有 `檔案系統` 首碼。 例如,`resolveLocalFileSystemURL` 的 `url` 參數應在表單 `filesystem:file:///persistent/somefile.txt` 而不是表單 `file:///persistent/somefile.txt` 在安卓系統。 -不推薦使用 `toNativeURL` 函數不受支援,並且沒有存根 (stub)。 -`setMetadata` 功能是沒有說出的規格,並且不支援。 -INVALID_MODIFICATION_ERR (代碼: 9) 而不是引發 SYNTAX_ERR(code: 8) 上請求一個不存在的檔案系統。 -INVALID_MODIFICATION_ERR (代碼: 9) 而不是引發 PATH_EXISTS_ERR(code: 12) 上嘗試專門創建一個檔或目錄,它已經存在。 -INVALID_MODIFICATION_ERR (代碼: 9) 而不是引發 NO_MODIFICATION_ALLOWED_ERR(code: 6) 在試圖調用 removeRecursively 的根檔案系統上。 -INVALID_MODIFICATION_ERR (代碼: 9) 而不是引發 NOT_FOUND_ERR(code: 1) 試到 moveTo 目錄不存在。 + +### 基於 IndexedDB 的 impl 怪癖 (Firefox 和 IE) + + * `.` 和 `.` 不受支援。 + * IE 不支援 `file:///`-模式 ;只有託管的模式是支援 (HTTP://localhost:xxxx)。 + * 火狐瀏覽器的檔案系統大小不是有限,但每個 50 MB 擴展會要求使用者的許可權。 IE10 允許達 10 mb 的 AppCache 和 IndexedDB 檔案系統的實現中使用而不會提示,一旦你達到這一水準你會詢問您是否允許它增加到每個網站的 250 mb 的最大合併。 所以 `requestFileSystem` 函數的 `大小` 參數並不影響檔案系統相容 Firefox 和 IE。 + * `readAsBinaryString` 函數在規範中沒有注明不支援在 IE 中和沒有存根 (stub)。 + * `file.type` 始終為 null。 + * 您不應創建條目使用已刪除的目錄實例回檔結果。否則,你會得到一個 '掛條目'。 + * 您可以讀取一個檔,其中只是寫之前你需要獲得的此檔的新實例。 + * `setMetadata` 函數,在規範中沒有注明支援 `modificationTime` 欄位的更改。 + * `copyTo` 和 `moveTo` 函數不支援目錄。 + * 不支援目錄的中繼資料。 + * 兩個 Entry.remove 和 directoryEntry.removeRecursively 不失敗時刪除非空的目錄-相反與內容一起清理目錄被刪除。 + * 不支援 `abort` 和 `truncate` 函數。 + * 進度事件不會觸發。例如,將不執行此處理程式: + +```javascript +writer.onprogress = function() { /*commands*/ }; +``` + +## 升級筆記 + +在這個外掛程式 v1.0.0,`FileEntry` 和 `DirectoryEntry` 的結構已經改變,以更加一致的已發表說明書。 + +以前 (pre-1.0.0) 版本的外掛程式中 `輸入` 物件的 `完整路徑` 屬性存放裝置固定檔案位置。這些路徑通常會看起來像 + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +這些路徑還返回的 `Entry` 物件的 `toURL()` 方法。 + +與 v1.0.0,`完整路徑` 屬性是到檔中,*相對於 HTML 檔案系統的根目錄* 的路徑。 因此,上述路徑會現在都由一個 `FileEntry` 物件的 `完整路徑`, + + /path/to/file + + +如果您的應用程式與設備-絕對路徑,並且您以前檢索到這些路徑通過 `條目` 物件的 `完整路徑` 屬性,然後您應該更新您的代碼以改用 `entry.toURL()`。 + +為向後相容性,`resolveLocalFileSystemURL()` 方法將接受一個設備-絕對路徑,並將返回相應的 `條目` 物件,只要在 `臨時` 或 `永久性` 的檔案系統內的檔是否存在。 + +這尤其是一直與檔案傳輸外掛程式,以前使用設備絕對路徑的問題 (和仍然可以接受他們)。 已更新它能夠正常運行與檔案系統的 Url,所以用 `entry.toURL()` 替換 `entry.fullPath` 應解決任何問題,得到該外掛程式來處理設備上的檔。 + +在 v1.1.0 `toURL()` 的傳回值被更改 (見 [CB-6394] (HTTPs://issues.apache.org/jira/browse/CB-6394)) 為返回絕對 file:// URL。 只要有可能。 確保 'cdvfile:' — — 你現在可以用 `toInternalURL()` 的 URL。 現在,此方法將返回檔案系統表單的 Url + + cdvfile://localhost/persistent/path/to/file + + +它可以用於唯一地標識該檔。 + +## 錯誤代碼及其含義的清單中 + +當拋出一個錯誤時,將使用以下代碼之一。 + +| 代碼 | 恒 | +| --:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## 配置外掛程式 (可選) + +可用的檔案系統的一整套可以配置每個平臺。IOS 和安卓系統認識到 在 `config.xml` 名稱要安裝的檔案系統中的標記。預設情況下,啟用所有檔案系統的根。 + + + + + +### Android 系統 + + * `files`: 該應用程式的內部檔存儲目錄 + * `files-external`: 應用程式的外部檔存儲目錄 + * `sdcard`: 全球外部檔存儲目錄 (如果安裝了一個,這是 SD 卡的根目錄)。 你必須具有 `android.permission.WRITE_EXTERNAL_STORAGE` 許可權,用這個。 + * `cache`: 應用程式的內部緩存目錄 + * `cache-external`: 應用程式的外部快取記憶體目錄 + * `root`: 整個設備的檔案系統 + +安卓系統還支援特殊的檔命名為"檔",表示"/ 檔 /""檔"的檔案系統中的子目錄。 + +### iOS + + * `library`: 應用程式的庫目錄 + * `documents`: 應用程式的檔目錄 + * `cache`: 應用程式的緩存目錄 + * `bundle`: 應用程式的包 ;應用程式本身 (唯讀) 的磁片上的位置 + * `root`: 整個設備的檔案系統 + +預設情況下,圖書館和檔目錄可以同步到 iCloud。 您也可以要求兩個額外的檔案系統、 `library-nosync` 和 `documents-nosync`,代表一個特殊的非同步目錄內 `/Library` 或 `/Documents` 的檔案系統。 \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/doc/zh/index.md b/mobile/plugins/cordova-plugin-file/doc/zh/index.md new file mode 100644 index 0000000..6eec44d --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/zh/index.md @@ -0,0 +1,343 @@ + + +# cordova-plugin-file + +這個外掛程式實現檔 API 允許對檔駐留在該設備上的讀/寫訪問。 + +這個外掛程式基於幾個規格,包括: HTML5 檔 API [HTTP://www.w3.org/TR/FileAPI/][1] + + [1]: http://www.w3.org/TR/FileAPI/ + +(現已解散) 目錄和系統擴展最新: [HTTP://www.w3.org/TR/2012/WD-file-system-api-20120417/][2]雖然大部分的外掛程式代碼寫時較早的規格是當前: [HTTP://www.w3.org/TR/2011/WD-file-system-api-20110419/][3] + + [2]: http://www.w3.org/TR/2012/WD-file-system-api-20120417/ + [3]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/ + +它還實現 FileWriter 規格: [HTTP://dev.w3.org/2009/dap/file-system/file-writer.html][4] + + [4]: http://dev.w3.org/2009/dap/file-system/file-writer.html + +用法,請參閱對 HTML5 的岩石優秀[檔案系統文章。][5] + + [5]: http://www.html5rocks.com/en/tutorials/file/filesystem/ + +其他存儲選項的概述,請參閱科爾多瓦的[存儲指南][6]. + + [6]: http://cordova.apache.org/docs/en/edge/cordova_storage_storage.md.html + +這個外掛程式定義全球 `cordova.file` 物件。 + +雖然在全球範圍內,它不可用直到 `deviceready` 事件之後。 + + document.addEventListener("deviceready", onDeviceReady, false); + function onDeviceReady() { + console.log(cordova.file); + } + + +## 安裝 + + cordova plugin add cordova-plugin-file + + +## 支援的平臺 + +* 亞馬遜火 OS +* Android 系統 +* 黑莓 10 +* 火狐瀏覽器的作業系統 +* iOS +* Windows Phone 7 和 8 * +* Windows 8 * +* 瀏覽器 + +* *這些平臺不支援 `FileReader.readAsArrayBuffer` 或 `FileWriter.write(blob)`.* + +## 存儲檔的位置 + +截至 v1.2.0,提供重要的檔案系統目錄的 Url。 每個 URL 位於表單 *file:///path/to/spot/*,和可以轉換為使用 `window.resolveLocalFileSystemURL()` 的 `DirectoryEntry`. + +* `cordova.file.applicationDirectory`-唯讀目錄在哪裡安裝的應用程式。(*iOS*、*安卓*、*黑莓 10*) + +* `cordova.file.applicationStorageDirectory`-根目錄下的應用程式的沙箱 ;在 iOS 上此位置是唯讀 (但特定的子目錄 [像 `/Documents` ] 都是讀寫)。 中包含的所有資料都是私有的應用程式。 ( *iOS*、*安卓*、*黑莓 10*) + +* `cordova.file.dataDirectory`資料持久性和私有資料存儲在內部記憶體使用的應用程式的沙箱內 (在安卓系統,如果你需要使用外部儲存體,使用 `.externalDataDirectory` )。 在 iOS,此目錄不與 iCloud 同步 (使用 `.syncedDataDirectory` )。 (*iOS*、*安卓*、*黑莓 10*) + +* `cordova.file.cacheDirectory`-緩存的資料檔案或您的應用程式重新可以輕鬆地創建的任何檔的目錄。 作業系統可能會刪除這些檔,該設備在存儲上運行低時,然而,應用程式不應依賴的作業系統,請刪除檔在這裡。 (*iOS*、*安卓*、*黑莓 10*) + +* `cordova.file.externalApplicationStorageDirectory`-應用程式外部存儲上的空間。(*安卓*) + +* `cordova.file.externalDataDirectory`-放在外部存儲特定于應用程式的資料檔案的位置。(*安卓*) + +* `cordova.file.externalCacheDirectory`-在外部存儲應用程式緩存。(*安卓*) + +* `cordova.file.externalRootDirectory`-外部存儲 (SD 卡) 的根。(*安卓*、*黑莓 10*) + +* `cordova.file.tempDirectory`-OS 可以清除時的空目錄會。 不依賴于 OS,以清除此目錄 ;您的應用程式,應總是移除作為適用的檔。 (*iOS*) + +* `cordova.file.syncedDataDirectory`-保存應同步 (例如到 iCloud) 的特定于應用程式的檔。(*iOS*) + +* `cordova.file.documentsDirectory`-檔私有的應用程式,但這是對其他應用程式 (例如 Office 檔) 有意義。(*iOS*) + +* `cordova.file.sharedDirectory`-對所有應用程式 (*黑莓 10*全域可用的檔) + +## 檔案系統佈局 + +雖然技術上實現的細節,它可以是很有必要瞭解如何 `cordova.file.*` 屬性對應到實體路徑在實際設備上。 + +### iOS 檔案系統佈局 + +| 設備路徑 | `cordova.file.*` | `iosExtraFileSystems` | r/w 嗎? | 持續性嗎? | OS 清除 | 同步 | 私人 | +|:------------------------------- |:--------------------------- |:--------------------- |:------:|:------:|:----------:|:---:|:--:| +| `/ 無功/移動/應用程式/< UUID > /` | applicationStorageDirectory | - | r | 不適用 | 不適用 | 不適用 | 是啊 | +|    `appname.app/` | applicationDirectory | 束 | r | 不適用 | 不適用 | 不適用 | 是啊 | +|       `www/` | - | - | r | 不適用 | 不適用 | 不適用 | 是啊 | +|    `Documents/` | documentsDirectory | 檔 | r/w | 是啊 | 無 | 是啊 | 是啊 | +|       `NoCloud/` | - | 檔 nosync | r/w | 是啊 | 無 | 無 | 是啊 | +|    `Library` | - | 圖書館 | r/w | 是啊 | 無 | 是嗎? | 是啊 | +|       `NoCloud/` | dataDirectory | 圖書館 nosync | r/w | 是啊 | 無 | 無 | 是啊 | +|       `Cloud/` | syncedDataDirectory | - | r/w | 是啊 | 無 | 是啊 | 是啊 | +|       `Caches/` | cacheDirectory | 快取記憶體 | r/w | 是啊 * | 是的 * * *| | 無 | 是啊 | +|    `tmp/` | tempDirectory | - | r/w | 沒有 * * | 是的 * * *| | 無 | 是啊 | + +* 檔堅持跨應用程式重新開機和升級,但是每當作業系統的欲望,可以清除此目錄。您的應用程式應該能夠重新創建任何內容可能會被刪除。 + +* * 檔可能會持續整個應用程式重新開機,但不要依賴此行為。 不保證檔在更新之間持續存在。 您的應用程式時適用,是應該刪除此目錄的檔,因為作業系統並不能保證何時 (或即使) 中刪除這些檔。 + +* * *| 作業系統可能會清除此目錄的內容,每當它感覺它是必要的但不要依賴于此。 你應該清除此目錄為適合您的應用程式。 + +### Android 的檔案系統佈局 + +| 設備路徑 | `cordova.file.*` | `AndroidExtraFileSystems` | r/w 嗎? | 持續性嗎? | OS 清除 | 私人 | +|:--------------------------------- |:----------------------------------- |:------------------------- |:------:|:-----:|:------:|:--:| +| `file:///android_asset/` | applicationDirectory | | r | 不適用 | 不適用 | 是啊 | +| `/ 資料資料/< 應用程式 id > /` | applicationStorageDirectory | - | r/w | 不適用 | 不適用 | 是啊 | +|    `cache` | cacheDirectory | 快取記憶體 | r/w | 是啊 | 是啊 * | 是啊 | +|    `files` | dataDirectory | 檔 | r/w | 是啊 | 無 | 是啊 | +|       `Documents` | | 檔 | r/w | 是啊 | 無 | 是啊 | +| `< sd 卡 > /` | externalRootDirectory | sd 卡 | r/w | 是啊 | 無 | 無 | +|    `Android/data//` | externalApplicationStorageDirectory | - | r/w | 是啊 | 無 | 無 | +|       `cache` | externalCacheDirectry | 外部快取記憶體 | r/w | 是啊 | 沒有 * * | 無 | +|       `files` | externalDataDirectory | 外部檔 | r/w | 是啊 | 無 | 無 | + +* 的作業系統可能會定期清除此目錄中,但不是依賴于這種行為。 清除此為適合您的應用程式的目錄的內容。 使用者應手動清除緩存,將刪除此目錄的內容。 + +* * 作業系統不會自動清除此目錄你是負責管理自己的內容。 使用者應手動清除緩存,目錄中的內容將被刪除。 + +**注**: 如果外部存儲無法裝入,`cordova.file.external*` 屬性為 `空`. + +### 黑莓 10 檔案系統佈局 + +| 設備路徑 | `cordova.file.*` | r/w 嗎? | 持續性嗎? | OS 清除 | 私人 | +|:---------------------------------------------------- |:--------------------------- |:------:|:-----:|:-----:|:--:| +| `file:///accounts/1000/appdata/ < 應用程式 id > /` | applicationStorageDirectory | r | 不適用 | 不適用 | 是啊 | +|    `app/native` | applicationDirectory | r | 不適用 | 不適用 | 是啊 | +|    `data/webviews/webfs/temporary/local__0` | cacheDirectory | r/w | 無 | 是啊 | 是啊 | +|    `data/webviews/webfs/persistent/local__0` | dataDirectory | r/w | 是啊 | 無 | 是啊 | +| `file:///accounts/1000/removable/sdcard` | externalRemovableDirectory | r/w | 是啊 | 無 | 無 | +| `file:///accounts/1000/shared` | sharedDirectory | r/w | 是啊 | 無 | 無 | + +*注意*: 當應用程式部署工作週邊時,所有路徑都是相對於 /accounts/1000-enterprise。 + +## Android 的怪癖 + +### Android 的持久性存儲位置 + +有很多有效的位置來存儲持久性檔在 Android 設備上。 請參閱 [此頁面][7] 的各種可能性進行廣泛討論。 + + [7]: http://developer.android.com/guide/topics/data/data-storage.html + +以前版本的外掛程式會選擇在啟動時,基於該設備是否聲稱 SD 卡 (或等效存儲分區) 展開,臨時和永久檔的位置。 如果被掛載 SD 卡,或一個大的內部存儲分區可用 (如 nexus 系列設備上) 然後持久性檔將存儲在該空間的根目錄中。 這意味著所有的科爾多瓦應用程式可以看到所有可用的檔在卡片上。 + +如果 SD 卡不是可用的那麼以前的版本中將存儲資料下的 `/data/data/`,其中隔離應用程式從彼此,但仍可能導致使用者之間共用的資料。 + +現在可以選擇是否將檔存儲在內部檔的存儲位置,或使用以前的邏輯,與您的應用程式的 `config.xml` 檔中的偏好。 要執行此操作,請將以下兩行之一添加到 `config.xml`: + + + + + + +如果這條線,沒有檔外掛程式將使用 `Compatibility` 作為預設值。如果首選項標記存在,並不是這些值之一,應用程式將無法啟動。 + +如果您的應用程式以前已被運到使用者,使用較舊的 (預 1.0) 版本的這個外掛程式,並具有持久性的檔,系統中存儲的檔,然後您應該設置 `Compatibility` 偏好。 切換到"Internal"的位置,將意味著現有使用者升級他們的應用程式可能無法訪問他們以前存儲的檔,具體取決於他們的設備。 + +如果您的應用程式是新的或以前從未有持久性的檔案系統中存儲檔,那麼通常建議使用 `Internal` 設置。 + +## iOS 的怪癖 + +* `cordova.file.applicationStorageDirectory`是唯讀的 ;試圖存儲內的根目錄中的檔將會失敗。 使用的另一個 `cordova.file.*` 為 iOS 定義的屬性 (只有 `applicationDirectory` 和 `applicationStorageDirectory` 都是唯讀)。 +* `FileReader.readAsText(blob, encoding)` + * `encoding`參數不受支援,而 utf-8 編碼總是效果。 + +### iOS 的持久性存儲位置 + +有兩個有效的位置來存儲持久性在 iOS 設備上的檔: 檔目錄和圖書館目錄。 以前版本的外掛程式永遠只能將持久性檔存儲在文檔目錄中。 這已經使所有應用程式檔可見在 iTunes,往往是無意為之,尤其是對於處理大量小檔的應用程式中,而不是生產供出口,該目錄的既定的目標是證件齊全的副作用。 + +現在可以選擇是否將檔存儲在檔或庫目錄,與您的應用程式的 `config.xml` 檔中的偏好。 要執行此操作,請將以下兩行之一添加到 `config.xml`: + + + + + + +如果這條線,沒有檔外掛程式將使用 `Compatibility` 作為預設值。如果首選項標記存在,並不是這些值之一,應用程式將無法啟動。 + +如果您的應用程式以前已被運到使用者,使用較舊的 (預 1.0) 版本的這個外掛程式,並具有持久性的檔,系統中存儲的檔,然後您應該設置 `Compatibility` 偏好。 切換到 `Library` 的位置,將意味著現有使用者升級他們的應用程式將無法訪問他們以前存儲的檔。 + +如果您的應用程式是新的或以前從未有持久性的檔案系統中存儲檔,那麼通常建議使用 `Internal` 設置。 + +## 火狐瀏覽器作業系統的怪癖 + +檔案系統 API 本身不支援火狐瀏覽器的作業系統,作為墊片在 indexedDB 上實現的。 + +* 不會失敗時刪除非空的目錄 +* 不支援中繼資料的目錄 +* 方法 `copyTo` 和 `moveTo` 不支援目錄 + +支援以下資料路徑: * `applicationDirectory`-使用 `xhr` 獲取與應用程式打包的本地檔。 `dataDirectory`-用於持久性的特定于應用程式的資料檔案。 `cacheDirectory`-生存應重新開機應用程式的快取檔案 (應用程式不應依賴作業系統來刪除檔在這裡)。 + +## 瀏覽器的怪癖 + +### 常見的怪癖和備註 + +* 每個瀏覽器使用其自己的沙箱檔案系統。IE 和火狐瀏覽器使用 IndexedDB 作為一個基地。所有瀏覽器都使用正斜杠作為路徑中的目錄分隔符號。 +* 目錄條目不得不先後創建。 例如,調用 `fs.root.getDirectory (' dir1/dir2 ',{create:true},successCallback,errorCallback)`,如果不存在 dir1 將失敗。 +* 外掛程式將請求使用者許可權,以便在應用程式初次開機使用持久性存儲。 +* 外掛程式支援 `cdvfile://localhost` (本地資源) 只。通過 `cdvfile` 不支援外部資源即. +* 該外掛程式不遵循 ["檔案系統 API 8.3 命名限制"][8]. +* Blob 和檔 ' `close` 功能不受支援。 +* `FileSaver` 和 `BlobBuilder` 不支援這個外掛程式,沒有存根 (stub)。 +* 該外掛程式不支援 `requestAllFileSystems`。這個功能也是缺少規範中。 +* 在目錄中的條目將不會被刪除,如果您使用 `create: true` 標誌為現有目錄。 +* 不支援通過建構函式創建的檔。你應該使用 entry.file 方法。 +* 每個瀏覽器使用它自己的形式為 blob 的 URL 引用。 +* 支援 `readAsDataURL` 功能,但在 Chrome 中的媒體類型取決於輸入副檔名,在 IE 中的媒體類型都始終空著 (這是 `純文字` 按照說明書一樣),在 Firefox 中的媒體類型始終是 `應用程式/八位位元組流`。 例如,如果內容是 `abcdefg` 然後火狐瀏覽器返回 `資料: 應用程式 / 八位位元組流 ; base64,YWJjZGVmZw = =`,即返回 `資料: ; base64,YWJjZGVmZw = =`,鉻返回 `資料: < 媒體類型根據擴展條目名稱 > ; base64,YWJjZGVmZw = =`. +* 在表單 `file:///persistent/path/to/entry` 火狐瀏覽器 IE),`toInternalURL` 返回的路徑。 鉻在表單 `cdvfile://localhost/persistent/file` 返回的路徑. + + [8]: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions + +### 鉻的怪癖 + +* 設備準備好事件之後,chrome 檔案系統並不能立即準備。作為一種變通方法,您可以訂閱到 `filePluginIsReady` 事件。示例: + + javascript + window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false); + + +你可以使用 `window.isFilePluginReadyRaised` 函數來檢查是否已經引發了事件。 -window.requestFileSystem 臨時和永久性檔案系統配額並不局限于鉻。 為增加中鉻的持久性存儲,您需要調用 `window.initPersistentFileSystem` 方法。 預設情況下,持久性存儲配額為 5 MB。 鉻需要 `— — 允許--訪問-從-檔` 通過 `file:///` 協定運行參數對 API 的支援。 -如果您使用標誌,將不更改 `檔` 物件 `{create:true}` 現有 `條目` 的時候。 -事件 `可取消` 屬性設置為 true 在 Chrome 中。 這是違反了 [規範][4]。 -中鉻的 `toURL` 函數返回 `檔案系統:`-首碼路徑具體取決於應用程式主機。 例如,`filesystem:file:///persistent/somefile.txt`,`filesystem:HTTP://localhost:8080/persistent/somefile.txt`。 -`toURL` 函數結果不包含尾部反斜線在目錄條目的情況下。 鉻雖然正確解析目錄帶斜杠落後的 url。 -`resolveLocalFileSystemURL` 方法需要入站的 `url` 必須具有 `檔案系統` 首碼。 例如,`resolveLocalFileSystemURL` 的 `url` 參數應在表單 `filesystem:file:///persistent/somefile.txt` 而不是表單 `file:///persistent/somefile.txt` 在安卓系統。 -不推薦使用 `toNativeURL` 函數不受支援,並且沒有存根 (stub)。 -`setMetadata` 功能是沒有說出的規格,並且不支援。 -INVALID_MODIFICATION_ERR (代碼: 9) 而不是引發 SYNTAX_ERR(code: 8) 上請求一個不存在的檔案系統。 -INVALID_MODIFICATION_ERR (代碼: 9) 而不是引發 PATH_EXISTS_ERR(code: 12) 上嘗試專門創建一個檔或目錄,它已經存在。 -INVALID_MODIFICATION_ERR (代碼: 9) 而不是引發 NO_MODIFICATION_ALLOWED_ERR(code: 6) 在試圖調用 removeRecursively 的根檔案系統上。 -INVALID_MODIFICATION_ERR (代碼: 9) 而不是引發 NOT_FOUND_ERR(code: 1) 試到 moveTo 目錄不存在。 + +### 基於 IndexedDB 的 impl 怪癖 (Firefox 和 IE) + +* `.` 和 `.` 不受支援。 +* IE 不支援 `file:///`-模式 ;只有託管的模式是支援 (HTTP://localhost:xxxx)。 +* 火狐瀏覽器的檔案系統大小不是有限,但每個 50 MB 擴展會要求使用者的許可權。 IE10 允許達 10 mb 的 AppCache 和 IndexedDB 檔案系統的實現中使用而不會提示,一旦你達到這一水準你會詢問您是否允許它增加到每個網站的 250 mb 的最大合併。 所以 `requestFileSystem` 函數的 `大小` 參數並不影響檔案系統相容 Firefox 和 IE。 +* `readAsBinaryString` 函數在規範中沒有注明不支援在 IE 中和沒有存根 (stub)。 +* `file.type` 始終為 null。 +* 您不應創建條目使用已刪除的目錄實例回檔結果。否則,你會得到一個 '掛條目'。 +* 您可以讀取一個檔,其中只是寫之前你需要獲得的此檔的新實例。 +* `setMetadata` 函數,在規範中沒有注明支援 `modificationTime` 欄位的更改。 +* `copyTo` 和 `moveTo` 函數不支援目錄。 +* 不支援目錄的中繼資料。 +* 兩個 Entry.remove 和 directoryEntry.removeRecursively 不失敗時刪除非空的目錄-相反與內容一起清理目錄被刪除。 +* 不支援 `abort` 和 `truncate` 函數。 +* 進度事件不會觸發。例如,將不執行此處理程式: + + javascript + writer.onprogress = function() { /*commands*/ }; + + +## 升級筆記 + +在這個外掛程式 v1.0.0,`FileEntry` 和 `DirectoryEntry` 的結構已經改變,以更加一致的已發表說明書。 + +以前 (pre-1.0.0) 版本的外掛程式中 `輸入` 物件的 `完整路徑` 屬性存放裝置固定檔案位置。這些路徑通常會看起來像 + + /var/mobile/Applications//Documents/path/to/file (iOS) + /storage/emulated/0/path/to/file (Android) + + +這些路徑還返回的 `Entry` 物件的 `toURL()` 方法。 + +與 v1.0.0,`完整路徑` 屬性是到檔中,*相對於 HTML 檔案系統的根目錄* 的路徑。 因此,上述路徑會現在都由一個 `FileEntry` 物件的 `完整路徑`, + + /path/to/file + + +如果您的應用程式與設備-絕對路徑,並且您以前檢索到這些路徑通過 `條目` 物件的 `完整路徑` 屬性,然後您應該更新您的代碼以改用 `entry.toURL()`。 + +為向後相容性,`resolveLocalFileSystemURL()` 方法將接受一個設備-絕對路徑,並將返回相應的 `條目` 物件,只要在 `臨時` 或 `永久性` 的檔案系統內的檔是否存在。 + +這尤其是一直與檔案傳輸外掛程式,以前使用設備絕對路徑的問題 (和仍然可以接受他們)。 已更新它能夠正常運行與檔案系統的 Url,所以用 `entry.toURL()` 替換 `entry.fullPath` 應解決任何問題,得到該外掛程式來處理設備上的檔。 + +在 v1.1.0 `toURL()` 的傳回值被更改 (見 [CB-6394] (HTTPs://issues.apache.org/jira/browse/CB-6394)) 為返回絕對 file:// URL。 只要有可能。 確保 'cdvfile:' — — 你現在可以用 `toInternalURL()` 的 URL。 現在,此方法將返回檔案系統表單的 Url + + cdvfile://localhost/persistent/path/to/file + + +它可以用於唯一地標識該檔。 + +## 錯誤代碼及其含義的清單中 + +當拋出一個錯誤時,將使用以下代碼之一。 + +| 代碼 | 恒 | +| --:|:----------------------------- | +| 1 | `NOT_FOUND_ERR` | +| 2 | `SECURITY_ERR` | +| 3 | `ABORT_ERR` | +| 4 | `NOT_READABLE_ERR` | +| 5 | `ENCODING_ERR` | +| 6 | `NO_MODIFICATION_ALLOWED_ERR` | +| 7 | `INVALID_STATE_ERR` | +| 8 | `SYNTAX_ERR` | +| 9 | `INVALID_MODIFICATION_ERR` | +| 10 | `QUOTA_EXCEEDED_ERR` | +| 11 | `TYPE_MISMATCH_ERR` | +| 12 | `PATH_EXISTS_ERR` | + +## 配置外掛程式 (可選) + +可用的檔案系統的一整套可以配置每個平臺。IOS 和安卓系統認識到 在 `config.xml` 名稱要安裝的檔案系統中的標記。預設情況下,啟用所有檔案系統的根。 + + + + + +### Android 系統 + +* `files`: 該應用程式的內部檔存儲目錄 +* `files-external`: 應用程式的外部檔存儲目錄 +* `sdcard`: 全球外部檔存儲目錄 (如果安裝了一個,這是 SD 卡的根目錄)。 你必須具有 `android.permission.WRITE_EXTERNAL_STORAGE` 許可權,用這個。 +* `cache`: 應用程式的內部緩存目錄 +* `cache-external`: 應用程式的外部快取記憶體目錄 +* `root`: 整個設備的檔案系統 + +安卓系統還支援特殊的檔命名為"檔",表示"/ 檔 /""檔"的檔案系統中的子目錄。 + +### iOS + +* `library`: 應用程式的庫目錄 +* `documents`: 應用程式的檔目錄 +* `cache`: 應用程式的緩存目錄 +* `bundle`: 應用程式的包 ;應用程式本身 (唯讀) 的磁片上的位置 +* `root`: 整個設備的檔案系統 + +預設情況下,圖書館和檔目錄可以同步到 iCloud。 您也可以要求兩個額外的檔案系統、 `library-nosync` 和 `documents-nosync`,代表一個特殊的非同步目錄內 `/Library` 或 `/Documents` 的檔案系統。 diff --git a/mobile/plugins/cordova-plugin-file/doc/zh/plugins.md b/mobile/plugins/cordova-plugin-file/doc/zh/plugins.md new file mode 100644 index 0000000..c9a2d61 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/doc/zh/plugins.md @@ -0,0 +1,101 @@ + + +# 外掛程式開發人員注意事項 + +這些筆記主要用於 Android 和 iOS 開發者想要編寫外掛程式的介面與使用檔外掛程式的檔案系統。 + +## 工作與科爾多瓦檔案系統 Url + +自從版本 1.0.0,這個外掛程式一直使用 Url 與 `cdvfile` 大橋,計畫為所有通信,而不是揭露 JavaScript 的原始設備檔案系統路徑。 + +在 JavaScript 方面,這意味著 FileEntry 和 DirectoryEntry 的物件有一個完整路徑屬性是相對於 HTML 檔案系統的根目錄。 如果你的外掛程式的 JavaScript API 接受一個 FileEntry 或 DirectoryEntry 的物件,你應該打電話給 `.toURL()` 對該物件之前將它從橋上傳遞給本機代碼。 + +### 轉換 cdvfile: / / fileystem 路徑的 Url + +需要寫入到檔案系統的外掛程式可能想要將接收的檔案系統 URL 轉換為實際的檔案系統位置。有做這,根據本機平臺的多種方式。 + +很重要的是要記住,並不是所有 `cdvfile://` Url 是可映射到設備上的實際檔。 某些 Url 可以指在設備上沒有代表的檔,或甚至可以引用遠端資源的資產。 由於這些可能性,外掛程式應始終測試是否回來時試圖將 Url 轉換成路徑得到有意義的結果。 + +#### 安卓系統 + +在 android 系統,最簡單的方法來轉換 `cdvfile://` 檔案系統路徑的 URL 是使用 `org.apache.cordova.CordovaResourceApi` 。 `CordovaResourceApi`有幾種方法,可處理 `cdvfile://` 網址: + + web 視圖是成員的外掛程式類 CordovaResourceApi resourceApi = webView.getResourceApi(); + + 獲取表示此檔在設備上,file:/// URL / / 或 URL 相同變的如果它不能映射到檔 Uri fileURL = resourceApi.remapUri(Uri.parse(cdvfileURL)); + + +它也是可以直接使用檔外掛程式: + + 導入 org.apache.cordova.file.FileUtils; + 導入 org.apache.cordova.file.FileSystem; + 導入 java.net.MalformedURLException; + + 得到檔外掛程式外掛程式管理器從 FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File"); + + 給定 URL,得到的路徑,因為它嘗試 {字串路徑 = filePlugin.filesystemPathForURL(cdvfileURL);} 趕上 (MalformedURLException e) {/ / 檔案系統 url 不承認} + + +要轉換到的路徑從 `cdvfile://` URL: + + 導入 org.apache.cordova.file.LocalFilesystemURL; + + 獲取設備的路徑,一個 LocalFilesystemURL 物件 / / 或如果它不能表示為 cdvfile 的 URL,則為 null。 + LocalFilesystemURL url = filePlugin.filesystemURLforLocalPath(path); + 得到的字串表示形式的 URL 物件字串 cdvfileURL = url.toString(); + + +如果你的外掛程式創建一個檔,並且您想要為它返回一個 FileEntry 物件,使用該檔的外掛程式: + + 返回一個 JSON 結構適合於回到 JavaScript,/ / 或如果此檔不是可表示為 cdvfile 的 URL,則為 null。 + JSONObject 條目 = filePlugin.getEntryForFile(file); + + +#### iOS + +科爾多瓦在 iOS 上的不使用相同 `CordovaResourceApi` 作為 android 系統的概念。在 iOS,應使用檔外掛程式 Url 和檔案系統路徑之間進行轉換。 + + 獲取一個物件,CDVFilesystem URL 從 url 字串 CDVFilesystemURL * = [CDVFilesystemURL fileSystemURLWithString:cdvfileURL]; + 獲取路徑 URL 物件,或為零,如果它不能映射到檔 NSString * 路徑 = [filePlugin filesystemPathForURL:url]; + + + CDVFilesystem URL 物件獲取設備的路徑,或 / / 為零,如果它不能表示為 cdvfile 的 URL。 + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + 得到的字串表示形式的 URL 物件 NSString * cdvfileURL = [url absoluteString]; + + +如果你的外掛程式創建一個檔,並且您想要為它返回一個 FileEntry 物件,使用該檔的外掛程式: + + CDVFilesystem URL 物件獲取設備的路徑,或 / / 為零,如果它不能表示為 cdvfile 的 URL。 + CDVFilesystemURL * url = [filePlugin fileSystemURLforLocalPath:path]; + 得到一個結構來返回進入 JavaScript NSDictionary * = [filePlugin makeEntryForLocalURL:url] + + +#### JavaScript + +在 JavaScript 中,得到 `cdvfile://` URL 從 FileEntry 或 DirectoryEntry 的物件,只需調用 `.toURL()` 對它: + + var cdvfileURL = entry.toURL(); + + +在外掛程式回應處理常式,將從返回的 FileEntry 結構轉換為實際的條目物件,處理常式代碼應該導入檔外掛程式和創建新的物件: + + 創建適當的條目物件 var 條目; + 如果 (entryStruct.isDirectory) {條目 = 新目錄 (entryStruct.name,entryStruct.fullPath,新 FileSystem(entryStruct.filesystemName));} 其他 {條目 = 新的 FileEntry (entryStruct.name,entryStruct.fullPath,新 FileSystem(entryStruct.filesystemName));} \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/package.json b/mobile/plugins/cordova-plugin-file/package.json new file mode 100644 index 0000000..ffe1662 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/package.json @@ -0,0 +1,57 @@ +{ + "name": "cordova-plugin-file", + "version": "4.3.1", + "description": "Cordova File Plugin", + "cordova": { + "id": "cordova-plugin-file", + "platforms": [ + "android", + "amazon-fireos", + "ubuntu", + "ios", + "osx", + "wp7", + "wp8", + "blackberry10", + "windows8", + "windows", + "firefoxos" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/apache/cordova-plugin-file" + }, + "keywords": [ + "cordova", + "file", + "ecosystem:cordova", + "cordova-android", + "cordova-amazon-fireos", + "cordova-ubuntu", + "cordova-ios", + "cordova-osx", + "cordova-wp7", + "cordova-wp8", + "cordova-blackberry10", + "cordova-windows8", + "cordova-windows", + "cordova-firefoxos" + ], + "scripts": { + "test": "npm run jshint", + "jshint": "node node_modules/jshint/bin/jshint www && node node_modules/jshint/bin/jshint src && node node_modules/jshint/bin/jshint tests" + }, + "author": "Apache Software Foundation", + "license": "Apache-2.0", + "engines": { + "cordovaDependencies": { + "5.0.0": { + "cordova": ">100" + } + } + }, + "devDependencies": { + "jshint": "^2.6.0" + } +} diff --git a/mobile/plugins/cordova-plugin-file/plugin.xml b/mobile/plugins/cordova-plugin-file/plugin.xml new file mode 100644 index 0000000..51affa2 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/plugin.xml @@ -0,0 +1,424 @@ + + + + + File + Cordova File Plugin + Apache 2.0 + cordova,file + https://git-wip-us.apache.org/repos/asf/cordova-plugin-file.git + https://issues.apache.org/jira/browse/CB/component/12320651 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The Android Persistent storage location now defaults to "Internal". Please check this plugin's README to see if your application needs any changes in its config.xml. + +If this is a new application no changes are required. + +If this is an update to an existing application that did not specify an "AndroidPersistentFileLocation" you may need to add: + + "<preference name="AndroidPersistentFileLocation" value="Compatibility" />" + +to config.xml in order for the application to find previously stored files. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/plugins/cordova-plugin-file/src/android/AssetFilesystem.java b/mobile/plugins/cordova-plugin-file/src/android/AssetFilesystem.java new file mode 100644 index 0000000..b035c40 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/AssetFilesystem.java @@ -0,0 +1,294 @@ +/* + 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.cordova.file; + +import android.content.res.AssetManager; +import android.net.Uri; + +import org.apache.cordova.CordovaResourceApi; +import org.apache.cordova.LOG; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.HashMap; +import java.util.Map; + +public class AssetFilesystem extends Filesystem { + + private final AssetManager assetManager; + + // A custom gradle hook creates the cdvasset.manifest file, which speeds up asset listing a tonne. + // See: http://stackoverflow.com/questions/16911558/android-assetmanager-list-incredibly-slow + private static Object listCacheLock = new Object(); + private static boolean listCacheFromFile; + private static Map listCache; + private static Map lengthCache; + + private static final String LOG_TAG = "AssetFilesystem"; + + private void lazyInitCaches() { + synchronized (listCacheLock) { + if (listCache == null) { + ObjectInputStream ois = null; + try { + ois = new ObjectInputStream(assetManager.open("cdvasset.manifest")); + listCache = (Map) ois.readObject(); + lengthCache = (Map) ois.readObject(); + listCacheFromFile = true; + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + // Asset manifest won't exist if the gradle hook isn't set up correctly. + } finally { + if (ois != null) { + try { + ois.close(); + } catch (IOException e) { + LOG.d(LOG_TAG, e.getLocalizedMessage()); + } + } + } + if (listCache == null) { + LOG.w("AssetFilesystem", "Asset manifest not found. Recursive copies and directory listing will be slow."); + listCache = new HashMap(); + } + } + } + } + + private String[] listAssets(String assetPath) throws IOException { + if (assetPath.startsWith("/")) { + assetPath = assetPath.substring(1); + } + if (assetPath.endsWith("/")) { + assetPath = assetPath.substring(0, assetPath.length() - 1); + } + lazyInitCaches(); + String[] ret = listCache.get(assetPath); + if (ret == null) { + if (listCacheFromFile) { + ret = new String[0]; + } else { + ret = assetManager.list(assetPath); + listCache.put(assetPath, ret); + } + } + return ret; + } + + private long getAssetSize(String assetPath) throws FileNotFoundException { + if (assetPath.startsWith("/")) { + assetPath = assetPath.substring(1); + } + lazyInitCaches(); + if (lengthCache != null) { + Long ret = lengthCache.get(assetPath); + if (ret == null) { + throw new FileNotFoundException("Asset not found: " + assetPath); + } + return ret; + } + CordovaResourceApi.OpenForReadResult offr = null; + try { + offr = resourceApi.openForRead(nativeUriForFullPath(assetPath)); + long length = offr.length; + if (length < 0) { + // available() doesn't always yield the file size, but for assets it does. + length = offr.inputStream.available(); + } + return length; + } catch (IOException e) { + FileNotFoundException fnfe = new FileNotFoundException("File not found: " + assetPath); + fnfe.initCause(e); + throw fnfe; + } finally { + if (offr != null) { + try { + offr.inputStream.close(); + } catch (IOException e) { + LOG.d(LOG_TAG, e.getLocalizedMessage()); + } + } + } + } + + public AssetFilesystem(AssetManager assetManager, CordovaResourceApi resourceApi) { + super(Uri.parse("file:///android_asset/"), "assets", resourceApi); + this.assetManager = assetManager; + } + + @Override + public Uri toNativeUri(LocalFilesystemURL inputURL) { + return nativeUriForFullPath(inputURL.path); + } + + @Override + public LocalFilesystemURL toLocalUri(Uri inputURL) { + if (!"file".equals(inputURL.getScheme())) { + return null; + } + File f = new File(inputURL.getPath()); + // Removes and duplicate /s (e.g. file:///a//b/c) + Uri resolvedUri = Uri.fromFile(f); + String rootUriNoTrailingSlash = rootUri.getEncodedPath(); + rootUriNoTrailingSlash = rootUriNoTrailingSlash.substring(0, rootUriNoTrailingSlash.length() - 1); + if (!resolvedUri.getEncodedPath().startsWith(rootUriNoTrailingSlash)) { + return null; + } + String subPath = resolvedUri.getEncodedPath().substring(rootUriNoTrailingSlash.length()); + // Strip leading slash + if (!subPath.isEmpty()) { + subPath = subPath.substring(1); + } + Uri.Builder b = new Uri.Builder() + .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL) + .authority("localhost") + .path(name); + if (!subPath.isEmpty()) { + b.appendEncodedPath(subPath); + } + if (isDirectory(subPath) || inputURL.getPath().endsWith("/")) { + // Add trailing / for directories. + b.appendEncodedPath(""); + } + return LocalFilesystemURL.parse(b.build()); + } + + private boolean isDirectory(String assetPath) { + try { + return listAssets(assetPath).length != 0; + } catch (IOException e) { + return false; + } + } + + @Override + public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException { + String pathNoSlashes = inputURL.path.substring(1); + if (pathNoSlashes.endsWith("/")) { + pathNoSlashes = pathNoSlashes.substring(0, pathNoSlashes.length() - 1); + } + + String[] files; + try { + files = listAssets(pathNoSlashes); + } catch (IOException e) { + FileNotFoundException fnfe = new FileNotFoundException(); + fnfe.initCause(e); + throw fnfe; + } + + LocalFilesystemURL[] entries = new LocalFilesystemURL[files.length]; + for (int i = 0; i < files.length; ++i) { + entries[i] = localUrlforFullPath(new File(inputURL.path, files[i]).getPath()); + } + return entries; + } + + @Override + public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, + String path, JSONObject options, boolean directory) + throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException { + if (options != null && options.optBoolean("create")) { + throw new UnsupportedOperationException("Assets are read-only"); + } + + // Check whether the supplied path is absolute or relative + if (directory && !path.endsWith("/")) { + path += "/"; + } + + LocalFilesystemURL requestedURL; + if (path.startsWith("/")) { + requestedURL = localUrlforFullPath(normalizePath(path)); + } else { + requestedURL = localUrlforFullPath(normalizePath(inputURL.path + "/" + path)); + } + + // Throws a FileNotFoundException if it doesn't exist. + getFileMetadataForLocalURL(requestedURL); + + boolean isDir = isDirectory(requestedURL.path); + if (directory && !isDir) { + throw new TypeMismatchException("path doesn't exist or is file"); + } else if (!directory && isDir) { + throw new TypeMismatchException("path doesn't exist or is directory"); + } + + // Return the directory + return makeEntryForURL(requestedURL); + } + + @Override + public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException { + JSONObject metadata = new JSONObject(); + long size = inputURL.isDirectory ? 0 : getAssetSize(inputURL.path); + try { + metadata.put("size", size); + metadata.put("type", inputURL.isDirectory ? "text/directory" : resourceApi.getMimeType(toNativeUri(inputURL))); + metadata.put("name", new File(inputURL.path).getName()); + metadata.put("fullPath", inputURL.path); + metadata.put("lastModifiedDate", 0); + } catch (JSONException e) { + return null; + } + return metadata; + } + + @Override + public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) { + return false; + } + + @Override + long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset, boolean isBinary) throws NoModificationAllowedException, IOException { + throw new NoModificationAllowedException("Assets are read-only"); + } + + @Override + long truncateFileAtURL(LocalFilesystemURL inputURL, long size) throws IOException, NoModificationAllowedException { + throw new NoModificationAllowedException("Assets are read-only"); + } + + @Override + String filesystemPathForURL(LocalFilesystemURL url) { + return new File(rootUri.getPath(), url.path).toString(); + } + + @Override + LocalFilesystemURL URLforFilesystemPath(String path) { + return null; + } + + @Override + boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException, NoModificationAllowedException { + throw new NoModificationAllowedException("Assets are read-only"); + } + + @Override + boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws NoModificationAllowedException { + throw new NoModificationAllowedException("Assets are read-only"); + } + +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/ContentFilesystem.java b/mobile/plugins/cordova-plugin-file/src/android/ContentFilesystem.java new file mode 100644 index 0000000..6b983c0 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/ContentFilesystem.java @@ -0,0 +1,223 @@ +/* + 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.cordova.file; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.DocumentsContract; +import android.provider.MediaStore; +import android.provider.OpenableColumns; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import org.apache.cordova.CordovaResourceApi; +import org.json.JSONException; +import org.json.JSONObject; + +public class ContentFilesystem extends Filesystem { + + private final Context context; + + public ContentFilesystem(Context context, CordovaResourceApi resourceApi) { + super(Uri.parse("content://"), "content", resourceApi); + this.context = context; + } + + @Override + public Uri toNativeUri(LocalFilesystemURL inputURL) { + String authorityAndPath = inputURL.uri.getEncodedPath().substring(this.name.length() + 2); + if (authorityAndPath.length() < 2) { + return null; + } + String ret = "content://" + authorityAndPath; + String query = inputURL.uri.getEncodedQuery(); + if (query != null) { + ret += '?' + query; + } + String frag = inputURL.uri.getEncodedFragment(); + if (frag != null) { + ret += '#' + frag; + } + return Uri.parse(ret); + } + + @Override + public LocalFilesystemURL toLocalUri(Uri inputURL) { + if (!"content".equals(inputURL.getScheme())) { + return null; + } + String subPath = inputURL.getEncodedPath(); + if (subPath.length() > 0) { + subPath = subPath.substring(1); + } + Uri.Builder b = new Uri.Builder() + .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL) + .authority("localhost") + .path(name) + .appendPath(inputURL.getAuthority()); + if (subPath.length() > 0) { + b.appendEncodedPath(subPath); + } + Uri localUri = b.encodedQuery(inputURL.getEncodedQuery()) + .encodedFragment(inputURL.getEncodedFragment()) + .build(); + return LocalFilesystemURL.parse(localUri); + } + + @Override + public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, + String fileName, JSONObject options, boolean directory) throws IOException, TypeMismatchException, JSONException { + throw new UnsupportedOperationException("getFile() not supported for content:. Use resolveLocalFileSystemURL instead."); + } + + @Override + public boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) + throws NoModificationAllowedException { + Uri contentUri = toNativeUri(inputURL); + try { + context.getContentResolver().delete(contentUri, null, null); + } catch (UnsupportedOperationException t) { + // Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator. + // The ContentResolver applies only when the file was registered in the + // first case, which is generally only the case with images. + NoModificationAllowedException nmae = new NoModificationAllowedException("Deleting not supported for content uri: " + contentUri); + nmae.initCause(t); + throw nmae; + } + return true; + } + + @Override + public boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) + throws NoModificationAllowedException { + throw new NoModificationAllowedException("Cannot remove content url"); + } + + @Override + public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException { + throw new UnsupportedOperationException("readEntriesAtLocalURL() not supported for content:. Use resolveLocalFileSystemURL instead."); + } + + @Override + public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException { + long size = -1; + long lastModified = 0; + Uri nativeUri = toNativeUri(inputURL); + String mimeType = resourceApi.getMimeType(nativeUri); + Cursor cursor = openCursorForURL(nativeUri); + try { + if (cursor != null && cursor.moveToFirst()) { + Long sizeForCursor = resourceSizeForCursor(cursor); + if (sizeForCursor != null) { + size = sizeForCursor.longValue(); + } + Long modified = lastModifiedDateForCursor(cursor); + if (modified != null) + lastModified = modified.longValue(); + } else { + // Some content providers don't support cursors at all! + CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(nativeUri); + size = offr.length; + } + } catch (IOException e) { + FileNotFoundException fnfe = new FileNotFoundException(); + fnfe.initCause(e); + throw fnfe; + } finally { + if (cursor != null) + cursor.close(); + } + + JSONObject metadata = new JSONObject(); + try { + metadata.put("size", size); + metadata.put("type", mimeType); + metadata.put("name", name); + metadata.put("fullPath", inputURL.path); + metadata.put("lastModifiedDate", lastModified); + } catch (JSONException e) { + return null; + } + return metadata; + } + + @Override + public long writeToFileAtURL(LocalFilesystemURL inputURL, String data, + int offset, boolean isBinary) throws NoModificationAllowedException { + throw new NoModificationAllowedException("Couldn't write to file given its content URI"); + } + @Override + public long truncateFileAtURL(LocalFilesystemURL inputURL, long size) + throws NoModificationAllowedException { + throw new NoModificationAllowedException("Couldn't truncate file given its content URI"); + } + + protected Cursor openCursorForURL(Uri nativeUri) { + ContentResolver contentResolver = context.getContentResolver(); + try { + return contentResolver.query(nativeUri, null, null, null, null); + } catch (UnsupportedOperationException e) { + return null; + } + } + + private Long resourceSizeForCursor(Cursor cursor) { + int columnIndex = cursor.getColumnIndex(OpenableColumns.SIZE); + if (columnIndex != -1) { + String sizeStr = cursor.getString(columnIndex); + if (sizeStr != null) { + return Long.parseLong(sizeStr); + } + } + return null; + } + + protected Long lastModifiedDateForCursor(Cursor cursor) { + int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED); + if (columnIndex == -1) { + columnIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED); + } + if (columnIndex != -1) { + String dateStr = cursor.getString(columnIndex); + if (dateStr != null) { + return Long.parseLong(dateStr); + } + } + return null; + } + + @Override + public String filesystemPathForURL(LocalFilesystemURL url) { + File f = resourceApi.mapUriToFile(toNativeUri(url)); + return f == null ? null : f.getAbsolutePath(); + } + + @Override + public LocalFilesystemURL URLforFilesystemPath(String path) { + // Returns null as we don't support reverse mapping back to content:// URLs + return null; + } + + @Override + public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) { + return true; + } +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/DirectoryManager.java b/mobile/plugins/cordova-plugin-file/src/android/DirectoryManager.java new file mode 100644 index 0000000..07af5ea --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/DirectoryManager.java @@ -0,0 +1,134 @@ +/* + 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.cordova.file; + +import android.os.Environment; +import android.os.StatFs; + +import java.io.File; + +/** + * This class provides file directory utilities. + * All file operations are performed on the SD card. + * + * It is used by the FileUtils class. + */ +public class DirectoryManager { + + @SuppressWarnings("unused") + private static final String LOG_TAG = "DirectoryManager"; + + /** + * Determine if a file or directory exists. + * @param name The name of the file to check. + * @return T=exists, F=not found + */ + public static boolean testFileExists(String name) { + boolean status; + + // If SD card exists + if ((testSaveLocationExists()) && (!name.equals(""))) { + File path = Environment.getExternalStorageDirectory(); + File newPath = constructFilePaths(path.toString(), name); + status = newPath.exists(); + } + // If no SD card + else { + status = false; + } + return status; + } + + /** + * Get the free space in external storage + * + * @return Size in KB or -1 if not available + */ + public static long getFreeExternalStorageSpace() { + String status = Environment.getExternalStorageState(); + long freeSpaceInBytes = 0; + + // Check if external storage exists + if (status.equals(Environment.MEDIA_MOUNTED)) { + freeSpaceInBytes = getFreeSpaceInBytes(Environment.getExternalStorageDirectory().getPath()); + } else { + // If no external storage then return -1 + return -1; + } + + return freeSpaceInBytes / 1024; + } + + /** + * Given a path return the number of free bytes in the filesystem containing the path. + * + * @param path to the file system + * @return free space in bytes + */ + public static long getFreeSpaceInBytes(String path) { + try { + StatFs stat = new StatFs(path); + long blockSize = stat.getBlockSize(); + long availableBlocks = stat.getAvailableBlocks(); + return availableBlocks * blockSize; + } catch (IllegalArgumentException e) { + // The path was invalid. Just return 0 free bytes. + return 0; + } + } + + /** + * Determine if SD card exists. + * + * @return T=exists, F=not found + */ + public static boolean testSaveLocationExists() { + String sDCardStatus = Environment.getExternalStorageState(); + boolean status; + + // If SD card is mounted + if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) { + status = true; + } + + // If no SD card + else { + status = false; + } + return status; + } + + /** + * Create a new file object from two file paths. + * + * @param file1 Base file path + * @param file2 Remaining file path + * @return File object + */ + private static File constructFilePaths (String file1, String file2) { + File newPath; + if (file2.startsWith(file1)) { + newPath = new File(file2); + } + else { + newPath = new File(file1 + "/" + file2); + } + return newPath; + } +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/EncodingException.java b/mobile/plugins/cordova-plugin-file/src/android/EncodingException.java new file mode 100644 index 0000000..e9e1653 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/EncodingException.java @@ -0,0 +1,29 @@ +/* + 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.cordova.file; + +@SuppressWarnings("serial") +public class EncodingException extends Exception { + + public EncodingException(String message) { + super(message); + } + +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/FileExistsException.java b/mobile/plugins/cordova-plugin-file/src/android/FileExistsException.java new file mode 100644 index 0000000..5c4d83d --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/FileExistsException.java @@ -0,0 +1,29 @@ +/* + 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.cordova.file; + +@SuppressWarnings("serial") +public class FileExistsException extends Exception { + + public FileExistsException(String msg) { + super(msg); + } + +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/FileUtils.java b/mobile/plugins/cordova-plugin-file/src/android/FileUtils.java new file mode 100644 index 0000000..2b88d52 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/FileUtils.java @@ -0,0 +1,1224 @@ +/* + 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.cordova.file; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.util.Base64; + +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.LOG; +import org.apache.cordova.PermissionHelper; +import org.apache.cordova.PluginResult; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.security.Permission; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; + +/** + * This class provides file and directory services to JavaScript. + */ +public class FileUtils extends CordovaPlugin { + private static final String LOG_TAG = "FileUtils"; + + public static int NOT_FOUND_ERR = 1; + public static int SECURITY_ERR = 2; + public static int ABORT_ERR = 3; + + public static int NOT_READABLE_ERR = 4; + public static int ENCODING_ERR = 5; + public static int NO_MODIFICATION_ALLOWED_ERR = 6; + public static int INVALID_STATE_ERR = 7; + public static int SYNTAX_ERR = 8; + public static int INVALID_MODIFICATION_ERR = 9; + public static int QUOTA_EXCEEDED_ERR = 10; + public static int TYPE_MISMATCH_ERR = 11; + public static int PATH_EXISTS_ERR = 12; + + /* + * Permission callback codes + */ + + public static final int ACTION_GET_FILE = 0; + public static final int ACTION_WRITE = 1; + public static final int ACTION_GET_DIRECTORY = 2; + + public static final int WRITE = 3; + public static final int READ = 4; + + public static int UNKNOWN_ERR = 1000; + + private boolean configured = false; + + private PendingRequests pendingRequests; + + + + /* + * We need both read and write when accessing the storage, I think. + */ + + private String [] permissions = { + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE }; + + // This field exists only to support getEntry, below, which has been deprecated + private static FileUtils filePlugin; + + private interface FileOp { + void run(JSONArray args) throws Exception; + } + + private ArrayList filesystems; + + public void registerFilesystem(Filesystem fs) { + if (fs != null && filesystemForName(fs.name)== null) { + this.filesystems.add(fs); + } + } + + private Filesystem filesystemForName(String name) { + for (Filesystem fs:filesystems) { + if (fs != null && fs.name != null && fs.name.equals(name)) { + return fs; + } + } + return null; + } + + protected String[] getExtraFileSystemsPreference(Activity activity) { + String fileSystemsStr = preferences.getString("androidextrafilesystems", "files,files-external,documents,sdcard,cache,cache-external,assets,root"); + return fileSystemsStr.split(","); + } + + protected void registerExtraFileSystems(String[] filesystems, HashMap availableFileSystems) { + HashSet installedFileSystems = new HashSet(); + + /* Register filesystems in order */ + for (String fsName : filesystems) { + if (!installedFileSystems.contains(fsName)) { + String fsRoot = availableFileSystems.get(fsName); + if (fsRoot != null) { + File newRoot = new File(fsRoot); + if (newRoot.mkdirs() || newRoot.isDirectory()) { + registerFilesystem(new LocalFilesystem(fsName, webView.getContext(), webView.getResourceApi(), newRoot)); + installedFileSystems.add(fsName); + } else { + LOG.d(LOG_TAG, "Unable to create root dir for filesystem \"" + fsName + "\", skipping"); + } + } else { + LOG.d(LOG_TAG, "Unrecognized extra filesystem identifier: " + fsName); + } + } + } + } + + protected HashMap getAvailableFileSystems(Activity activity) { + Context context = activity.getApplicationContext(); + HashMap availableFileSystems = new HashMap(); + + availableFileSystems.put("files", context.getFilesDir().getAbsolutePath()); + availableFileSystems.put("documents", new File(context.getFilesDir(), "Documents").getAbsolutePath()); + availableFileSystems.put("cache", context.getCacheDir().getAbsolutePath()); + availableFileSystems.put("root", "/"); + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + try { + availableFileSystems.put("files-external", context.getExternalFilesDir(null).getAbsolutePath()); + availableFileSystems.put("sdcard", Environment.getExternalStorageDirectory().getAbsolutePath()); + availableFileSystems.put("cache-external", context.getExternalCacheDir().getAbsolutePath()); + } + catch(NullPointerException e) { + LOG.d(LOG_TAG, "External storage unavailable, check to see if USB Mass Storage Mode is on"); + } + } + + return availableFileSystems; + } + + @Override + public void initialize(CordovaInterface cordova, CordovaWebView webView) { + super.initialize(cordova, webView); + this.filesystems = new ArrayList(); + this.pendingRequests = new PendingRequests(); + + String tempRoot = null; + String persistentRoot = null; + + Activity activity = cordova.getActivity(); + String packageName = activity.getPackageName(); + + String location = preferences.getString("androidpersistentfilelocation", "internal"); + + tempRoot = activity.getCacheDir().getAbsolutePath(); + if ("internal".equalsIgnoreCase(location)) { + persistentRoot = activity.getFilesDir().getAbsolutePath() + "/files/"; + this.configured = true; + } else if ("compatibility".equalsIgnoreCase(location)) { + /* + * Fall-back to compatibility mode -- this is the logic implemented in + * earlier versions of this plugin, and should be maintained here so + * that apps which were originally deployed with older versions of the + * plugin can continue to provide access to files stored under those + * versions. + */ + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + persistentRoot = Environment.getExternalStorageDirectory().getAbsolutePath(); + tempRoot = Environment.getExternalStorageDirectory().getAbsolutePath() + + "/Android/data/" + packageName + "/cache/"; + } else { + persistentRoot = "/data/data/" + packageName; + } + this.configured = true; + } + + if (this.configured) { + // Create the directories if they don't exist. + File tmpRootFile = new File(tempRoot); + File persistentRootFile = new File(persistentRoot); + tmpRootFile.mkdirs(); + persistentRootFile.mkdirs(); + + // Register initial filesystems + // Note: The temporary and persistent filesystems need to be the first two + // registered, so that they will match window.TEMPORARY and window.PERSISTENT, + // per spec. + this.registerFilesystem(new LocalFilesystem("temporary", webView.getContext(), webView.getResourceApi(), tmpRootFile)); + this.registerFilesystem(new LocalFilesystem("persistent", webView.getContext(), webView.getResourceApi(), persistentRootFile)); + this.registerFilesystem(new ContentFilesystem(webView.getContext(), webView.getResourceApi())); + this.registerFilesystem(new AssetFilesystem(webView.getContext().getAssets(), webView.getResourceApi())); + + registerExtraFileSystems(getExtraFileSystemsPreference(activity), getAvailableFileSystems(activity)); + + // Initialize static plugin reference for deprecated getEntry method + if (filePlugin == null) { + FileUtils.filePlugin = this; + } + } else { + LOG.e(LOG_TAG, "File plugin configuration error: Please set AndroidPersistentFileLocation in config.xml to one of \"internal\" (for new applications) or \"compatibility\" (for compatibility with previous versions)"); + activity.finish(); + } + } + + public static FileUtils getFilePlugin() { + return filePlugin; + } + + private Filesystem filesystemForURL(LocalFilesystemURL localURL) { + if (localURL == null) return null; + return filesystemForName(localURL.fsName); + } + + @Override + public Uri remapUri(Uri uri) { + // Remap only cdvfile: URLs (not content:). + if (!LocalFilesystemURL.FILESYSTEM_PROTOCOL.equals(uri.getScheme())) { + return null; + } + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(uri); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + return null; + } + String path = fs.filesystemPathForURL(inputURL); + if (path != null) { + return Uri.parse("file://" + fs.filesystemPathForURL(inputURL)); + } + return null; + } catch (IllegalArgumentException e) { + return null; + } + } + + public boolean execute(String action, final String rawArgs, final CallbackContext callbackContext) { + if (!configured) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "File plugin is not configured. Please see the README.md file for details on how to update config.xml")); + return true; + } + if (action.equals("testSaveLocationExists")) { + threadhelper(new FileOp() { + public void run(JSONArray args) { + boolean b = DirectoryManager.testSaveLocationExists(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b)); + } + }, rawArgs, callbackContext); + } + else if (action.equals("getFreeDiskSpace")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) { + // The getFreeDiskSpace plugin API is not documented, but some apps call it anyway via exec(). + // For compatibility it always returns free space in the primary external storage, and + // does NOT fallback to internal store if external storage is unavailable. + long l = DirectoryManager.getFreeExternalStorageSpace(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, l)); + } + }, rawArgs, callbackContext); + } + else if (action.equals("testFileExists")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException { + String fname=args.getString(0); + boolean b = DirectoryManager.testFileExists(fname); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b)); + } + }, rawArgs, callbackContext); + } + else if (action.equals("testDirectoryExists")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException { + String fname=args.getString(0); + boolean b = DirectoryManager.testFileExists(fname); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b)); + } + }, rawArgs, callbackContext); + } + else if (action.equals("readAsText")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, MalformedURLException { + String encoding = args.getString(1); + int start = args.getInt(2); + int end = args.getInt(3); + String fname=args.getString(0); + readFileAs(fname, start, end, callbackContext, encoding, PluginResult.MESSAGE_TYPE_STRING); + } + }, rawArgs, callbackContext); + } + else if (action.equals("readAsDataURL")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, MalformedURLException { + int start = args.getInt(1); + int end = args.getInt(2); + String fname=args.getString(0); + readFileAs(fname, start, end, callbackContext, null, -1); + } + }, rawArgs, callbackContext); + } + else if (action.equals("readAsArrayBuffer")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, MalformedURLException { + int start = args.getInt(1); + int end = args.getInt(2); + String fname=args.getString(0); + readFileAs(fname, start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_ARRAYBUFFER); + } + }, rawArgs, callbackContext); + } + else if (action.equals("readAsBinaryString")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, MalformedURLException { + int start = args.getInt(1); + int end = args.getInt(2); + String fname=args.getString(0); + readFileAs(fname, start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_BINARYSTRING); + } + }, rawArgs, callbackContext); + } + else if (action.equals("write")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, FileNotFoundException, IOException, NoModificationAllowedException { + String fname=args.getString(0); + String nativeURL = resolveLocalFileSystemURI(fname).getString("nativeURL"); + String data=args.getString(1); + int offset=args.getInt(2); + Boolean isBinary=args.getBoolean(3); + + if(needPermission(nativeURL, WRITE)) { + getWritePermission(rawArgs, ACTION_WRITE, callbackContext); + } + else { + long fileSize = write(fname, data, offset, isBinary); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize)); + } + + } + }, rawArgs, callbackContext); + } + else if (action.equals("truncate")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, FileNotFoundException, IOException, NoModificationAllowedException { + String fname=args.getString(0); + int offset=args.getInt(1); + long fileSize = truncateFile(fname, offset); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize)); + } + }, rawArgs, callbackContext); + } + else if (action.equals("requestAllFileSystems")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws IOException, JSONException { + callbackContext.success(requestAllFileSystems()); + } + }, rawArgs, callbackContext); + } else if (action.equals("requestAllPaths")) { + cordova.getThreadPool().execute( + new Runnable() { + public void run() { + try { + callbackContext.success(requestAllPaths()); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + ); + } else if (action.equals("requestFileSystem")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException { + int fstype = args.getInt(0); + long requiredSize = args.optLong(1); + requestFileSystem(fstype, requiredSize, callbackContext); + } + }, rawArgs, callbackContext); + } + else if (action.equals("resolveLocalFileSystemURI")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws IOException, JSONException { + String fname=args.getString(0); + JSONObject obj = resolveLocalFileSystemURI(fname); + callbackContext.success(obj); + } + }, rawArgs, callbackContext); + } + else if (action.equals("getFileMetadata")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws FileNotFoundException, JSONException, MalformedURLException { + String fname=args.getString(0); + JSONObject obj = getFileMetadata(fname); + callbackContext.success(obj); + } + }, rawArgs, callbackContext); + } + else if (action.equals("getParent")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, IOException { + String fname=args.getString(0); + JSONObject obj = getParent(fname); + callbackContext.success(obj); + } + }, rawArgs, callbackContext); + } + else if (action.equals("getDirectory")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException { + String dirname = args.getString(0); + String path = args.getString(1); + String nativeURL = resolveLocalFileSystemURI(dirname).getString("nativeURL"); + boolean containsCreate = (args.isNull(2)) ? false : args.getJSONObject(2).optBoolean("create", false); + + if(containsCreate && needPermission(nativeURL, WRITE)) { + getWritePermission(rawArgs, ACTION_GET_DIRECTORY, callbackContext); + } + else if(!containsCreate && needPermission(nativeURL, READ)) { + getReadPermission(rawArgs, ACTION_GET_DIRECTORY, callbackContext); + } + else { + JSONObject obj = getFile(dirname, path, args.optJSONObject(2), true); + callbackContext.success(obj); + } + } + }, rawArgs, callbackContext); + } + else if (action.equals("getFile")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException { + String dirname = args.getString(0); + String path = args.getString(1); + String nativeURL = resolveLocalFileSystemURI(dirname).getString("nativeURL"); + boolean containsCreate = (args.isNull(2)) ? false : args.getJSONObject(2).optBoolean("create", false); + + if(containsCreate && needPermission(nativeURL, WRITE)) { + getWritePermission(rawArgs, ACTION_GET_FILE, callbackContext); + } + else if(!containsCreate && needPermission(nativeURL, READ)) { + getReadPermission(rawArgs, ACTION_GET_FILE, callbackContext); + } + else { + JSONObject obj = getFile(dirname, path, args.optJSONObject(2), false); + callbackContext.success(obj); + } + } + }, rawArgs, callbackContext); + } + else if (action.equals("remove")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, NoModificationAllowedException, InvalidModificationException, MalformedURLException { + String fname=args.getString(0); + boolean success = remove(fname); + if (success) { + callbackContext.success(); + } else { + callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR); + } + } + }, rawArgs, callbackContext); + } + else if (action.equals("removeRecursively")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, FileExistsException, MalformedURLException, NoModificationAllowedException { + String fname=args.getString(0); + boolean success = removeRecursively(fname); + if (success) { + callbackContext.success(); + } else { + callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR); + } + } + }, rawArgs, callbackContext); + } + else if (action.equals("moveTo")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException { + String fname=args.getString(0); + String newParent=args.getString(1); + String newName=args.getString(2); + JSONObject entry = transferTo(fname, newParent, newName, true); + callbackContext.success(entry); + } + }, rawArgs, callbackContext); + } + else if (action.equals("copyTo")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException { + String fname=args.getString(0); + String newParent=args.getString(1); + String newName=args.getString(2); + JSONObject entry = transferTo(fname, newParent, newName, false); + callbackContext.success(entry); + } + }, rawArgs, callbackContext); + } + else if (action.equals("readEntries")) { + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws FileNotFoundException, JSONException, MalformedURLException { + String fname=args.getString(0); + JSONArray entries = readEntries(fname); + callbackContext.success(entries); + } + }, rawArgs, callbackContext); + } + else if (action.equals("_getLocalFilesystemPath")) { + // Internal method for testing: Get the on-disk location of a local filesystem url. + // [Currently used for testing file-transfer] + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws FileNotFoundException, JSONException, MalformedURLException { + String localURLstr = args.getString(0); + String fname = filesystemPathForURL(localURLstr); + callbackContext.success(fname); + } + }, rawArgs, callbackContext); + } + else { + return false; + } + return true; + } + + private void getReadPermission(String rawArgs, int action, CallbackContext callbackContext) { + int requestCode = pendingRequests.createRequest(rawArgs, action, callbackContext); + PermissionHelper.requestPermission(this, requestCode, Manifest.permission.READ_EXTERNAL_STORAGE); + } + + private void getWritePermission(String rawArgs, int action, CallbackContext callbackContext) { + int requestCode = pendingRequests.createRequest(rawArgs, action, callbackContext); + PermissionHelper.requestPermission(this, requestCode, Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + + private boolean hasReadPermission() { + return PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); + } + + private boolean hasWritePermission() { + return PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + + private boolean needPermission(String nativeURL, int permissionType) throws JSONException { + JSONObject j = requestAllPaths(); + ArrayList allowedStorageDirectories = new ArrayList(); + allowedStorageDirectories.add(j.getString("applicationStorageDirectory")); + if(j.has("externalApplicationStorageDirectory")) { + allowedStorageDirectories.add(j.getString("externalApplicationStorageDirectory")); + } + + if(permissionType == READ && hasReadPermission()) { + return false; + } + else if(permissionType == WRITE && hasWritePermission()) { + return false; + } + + // Permission required if the native url lies outside the allowed storage directories + for(String directory : allowedStorageDirectories) { + if(nativeURL.startsWith(directory)) { + return false; + } + } + return true; + } + + + public LocalFilesystemURL resolveNativeUri(Uri nativeUri) { + LocalFilesystemURL localURL = null; + + // Try all installed filesystems. Return the best matching URL + // (determined by the shortest resulting URL) + for (Filesystem fs : filesystems) { + LocalFilesystemURL url = fs.toLocalUri(nativeUri); + if (url != null) { + // A shorter fullPath implies that the filesystem is a better + // match for the local path than the previous best. + if (localURL == null || (url.uri.toString().length() < localURL.toString().length())) { + localURL = url; + } + } + } + return localURL; + } + + /* + * These two native-only methods can be used by other plugins to translate between + * device file system paths and URLs. By design, there is no direct JavaScript + * interface to these methods. + */ + + public String filesystemPathForURL(String localURLstr) throws MalformedURLException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(localURLstr); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + return fs.filesystemPathForURL(inputURL); + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + } + + public LocalFilesystemURL filesystemURLforLocalPath(String localPath) { + LocalFilesystemURL localURL = null; + int shortestFullPath = 0; + + // Try all installed filesystems. Return the best matching URL + // (determined by the shortest resulting URL) + for (Filesystem fs: filesystems) { + LocalFilesystemURL url = fs.URLforFilesystemPath(localPath); + if (url != null) { + // A shorter fullPath implies that the filesystem is a better + // match for the local path than the previous best. + if (localURL == null || (url.path.length() < shortestFullPath)) { + localURL = url; + shortestFullPath = url.path.length(); + } + } + } + return localURL; + } + + + /* helper to execute functions async and handle the result codes + * + */ + private void threadhelper(final FileOp f, final String rawArgs, final CallbackContext callbackContext){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + JSONArray args = new JSONArray(rawArgs); + f.run(args); + } catch ( Exception e) { + if( e instanceof EncodingException){ + callbackContext.error(FileUtils.ENCODING_ERR); + } else if(e instanceof FileNotFoundException) { + callbackContext.error(FileUtils.NOT_FOUND_ERR); + } else if(e instanceof FileExistsException) { + callbackContext.error(FileUtils.PATH_EXISTS_ERR); + } else if(e instanceof NoModificationAllowedException ) { + callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR); + } else if(e instanceof InvalidModificationException ) { + callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR); + } else if(e instanceof MalformedURLException ) { + callbackContext.error(FileUtils.ENCODING_ERR); + } else if(e instanceof IOException ) { + callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR); + } else if(e instanceof EncodingException ) { + callbackContext.error(FileUtils.ENCODING_ERR); + } else if(e instanceof TypeMismatchException ) { + callbackContext.error(FileUtils.TYPE_MISMATCH_ERR); + } else if(e instanceof JSONException ) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION)); + } else if (e instanceof SecurityException) { + callbackContext.error(FileUtils.SECURITY_ERR); + } else { + e.printStackTrace(); + callbackContext.error(FileUtils.UNKNOWN_ERR); + } + } + } + }); + } + + /** + * Allows the user to look up the Entry for a file or directory referred to by a local URI. + * + * @param uriString of the file/directory to look up + * @return a JSONObject representing a Entry from the filesystem + * @throws MalformedURLException if the url is not valid + * @throws FileNotFoundException if the file does not exist + * @throws IOException if the user can't read the file + * @throws JSONException + */ + private JSONObject resolveLocalFileSystemURI(String uriString) throws IOException, JSONException { + if (uriString == null) { + throw new MalformedURLException("Unrecognized filesystem URL"); + } + Uri uri = Uri.parse(uriString); + boolean isNativeUri = false; + + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(uri); + if (inputURL == null) { + /* Check for file://, content:// urls */ + inputURL = resolveNativeUri(uri); + isNativeUri = true; + } + + try { + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + if (fs.exists(inputURL)) { + if (!isNativeUri) { + // If not already resolved as native URI, resolve to a native URI and back to + // fix the terminating slash based on whether the entry is a directory or file. + inputURL = fs.toLocalUri(fs.toNativeUri(inputURL)); + } + + return fs.getEntryForLocalURL(inputURL); + } + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + throw new FileNotFoundException(); + } + + /** + * Read the list of files from this directory. + * + * @return a JSONArray containing JSONObjects that represent Entry objects. + * @throws FileNotFoundException if the directory is not found. + * @throws JSONException + * @throws MalformedURLException + */ + private JSONArray readEntries(String baseURLstr) throws FileNotFoundException, JSONException, MalformedURLException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + return fs.readEntriesAtLocalURL(inputURL); + + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + } + + /** + * A setup method that handles the move/copy of files/directories + * + * @param newName for the file directory to be called, if null use existing file name + * @param move if false do a copy, if true do a move + * @return a Entry object + * @throws NoModificationAllowedException + * @throws IOException + * @throws InvalidModificationException + * @throws EncodingException + * @throws JSONException + * @throws FileExistsException + */ + private JSONObject transferTo(String srcURLstr, String destURLstr, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException { + if (srcURLstr == null || destURLstr == null) { + // either no source or no destination provided + throw new FileNotFoundException(); + } + + LocalFilesystemURL srcURL = LocalFilesystemURL.parse(srcURLstr); + LocalFilesystemURL destURL = LocalFilesystemURL.parse(destURLstr); + + Filesystem srcFs = this.filesystemForURL(srcURL); + Filesystem destFs = this.filesystemForURL(destURL); + + // Check for invalid file name + if (newName != null && newName.contains(":")) { + throw new EncodingException("Bad file name"); + } + + return destFs.copyFileToURL(destURL, newName, srcFs, srcURL, move); + } + + /** + * Deletes a directory and all of its contents, if any. In the event of an error + * [e.g. trying to delete a directory that contains a file that cannot be removed], + * some of the contents of the directory may be deleted. + * It is an error to attempt to delete the root directory of a filesystem. + * + * @return a boolean representing success of failure + * @throws FileExistsException + * @throws NoModificationAllowedException + * @throws MalformedURLException + */ + private boolean removeRecursively(String baseURLstr) throws FileExistsException, NoModificationAllowedException, MalformedURLException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr); + // You can't delete the root directory. + if ("".equals(inputURL.path) || "/".equals(inputURL.path)) { + throw new NoModificationAllowedException("You can't delete the root directory"); + } + + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + return fs.recursiveRemoveFileAtLocalURL(inputURL); + + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + } + + + /** + * Deletes a file or directory. It is an error to attempt to delete a directory that is not empty. + * It is an error to attempt to delete the root directory of a filesystem. + * + * @return a boolean representing success of failure + * @throws NoModificationAllowedException + * @throws InvalidModificationException + * @throws MalformedURLException + */ + private boolean remove(String baseURLstr) throws NoModificationAllowedException, InvalidModificationException, MalformedURLException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr); + // You can't delete the root directory. + if ("".equals(inputURL.path) || "/".equals(inputURL.path)) { + + throw new NoModificationAllowedException("You can't delete the root directory"); + } + + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + return fs.removeFileAtLocalURL(inputURL); + + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + } + + /** + * Creates or looks up a file. + * + * @param baseURLstr base directory + * @param path file/directory to lookup or create + * @param options specify whether to create or not + * @param directory if true look up directory, if false look up file + * @return a Entry object + * @throws FileExistsException + * @throws IOException + * @throws TypeMismatchException + * @throws EncodingException + * @throws JSONException + */ + private JSONObject getFile(String baseURLstr, String path, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + return fs.getFileForLocalURL(inputURL, path, options, directory); + + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + + } + + /** + * Look up the parent DirectoryEntry containing this Entry. + * If this Entry is the root of its filesystem, its parent is itself. + */ + private JSONObject getParent(String baseURLstr) throws JSONException, IOException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + return fs.getParentForLocalURL(inputURL); + + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + } + + /** + * Returns a File that represents the current state of the file that this FileEntry represents. + * + * @return returns a JSONObject represent a W3C File object + */ + private JSONObject getFileMetadata(String baseURLstr) throws FileNotFoundException, JSONException, MalformedURLException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + return fs.getFileMetadataForLocalURL(inputURL); + + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + } + + /** + * Requests a filesystem in which to store application data. + * + * @param type of file system requested + * @param requiredSize required free space in the file system in bytes + * @param callbackContext context for returning the result or error + * @throws JSONException + */ + private void requestFileSystem(int type, long requiredSize, final CallbackContext callbackContext) throws JSONException { + Filesystem rootFs = null; + try { + rootFs = this.filesystems.get(type); + } catch (ArrayIndexOutOfBoundsException e) { + // Pass null through + } + if (rootFs == null) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, FileUtils.NOT_FOUND_ERR)); + } else { + // If a nonzero required size was specified, check that the retrieved filesystem has enough free space. + long availableSize = 0; + if (requiredSize > 0) { + availableSize = rootFs.getFreeSpaceInBytes(); + } + + if (availableSize < requiredSize) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, FileUtils.QUOTA_EXCEEDED_ERR)); + } else { + JSONObject fs = new JSONObject(); + fs.put("name", rootFs.name); + fs.put("root", rootFs.getRootEntry()); + callbackContext.success(fs); + } + } + } + + /** + * Requests a filesystem in which to store application data. + * + * @return a JSONObject representing the file system + */ + private JSONArray requestAllFileSystems() throws IOException, JSONException { + JSONArray ret = new JSONArray(); + for (Filesystem fs : filesystems) { + ret.put(fs.getRootEntry()); + } + return ret; + } + + private static String toDirUrl(File f) { + return Uri.fromFile(f).toString() + '/'; + } + + private JSONObject requestAllPaths() throws JSONException { + Context context = cordova.getActivity(); + JSONObject ret = new JSONObject(); + ret.put("applicationDirectory", "file:///android_asset/"); + ret.put("applicationStorageDirectory", toDirUrl(context.getFilesDir().getParentFile())); + ret.put("dataDirectory", toDirUrl(context.getFilesDir())); + ret.put("cacheDirectory", toDirUrl(context.getCacheDir())); + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + try { + ret.put("externalApplicationStorageDirectory", toDirUrl(context.getExternalFilesDir(null).getParentFile())); + ret.put("externalDataDirectory", toDirUrl(context.getExternalFilesDir(null))); + ret.put("externalCacheDirectory", toDirUrl(context.getExternalCacheDir())); + ret.put("externalRootDirectory", toDirUrl(Environment.getExternalStorageDirectory())); + } + catch(NullPointerException e) { + /* If external storage is unavailable, context.getExternal* returns null */ + LOG.d(LOG_TAG, "Unable to access these paths, most liklely due to USB storage"); + } + } + return ret; + } + + /** + * Returns a JSON object representing the given File. Internal APIs should be modified + * to use URLs instead of raw FS paths wherever possible, when interfacing with this plugin. + * + * @param file the File to convert + * @return a JSON representation of the given File + * @throws JSONException + */ + public JSONObject getEntryForFile(File file) throws JSONException { + JSONObject entry; + + for (Filesystem fs : filesystems) { + entry = fs.makeEntryForFile(file); + if (entry != null) { + return entry; + } + } + return null; + } + + /** + * Returns a JSON object representing the given File. Deprecated, as this is only used by + * FileTransfer, and because it is a static method that should really be an instance method, + * since it depends on the actual filesystem roots in use. Internal APIs should be modified + * to use URLs instead of raw FS paths wherever possible, when interfacing with this plugin. + * + * @param file the File to convert + * @return a JSON representation of the given File + * @throws JSONException + */ + @Deprecated + public static JSONObject getEntry(File file) throws JSONException { + if (getFilePlugin() != null) { + return getFilePlugin().getEntryForFile(file); + } + return null; + } + + /** + * Read the contents of a file. + * This is done in a background thread; the result is sent to the callback. + * + * @param start Start position in the file. + * @param end End position to stop at (exclusive). + * @param callbackContext The context through which to send the result. + * @param encoding The encoding to return contents as. Typical value is UTF-8. (see http://www.iana.org/assignments/character-sets) + * @param resultType The desired type of data to send to the callback. + * @return Contents of file. + */ + public void readFileAs(final String srcURLstr, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) throws MalformedURLException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + + fs.readFileAtURL(inputURL, start, end, new Filesystem.ReadFileCallback() { + public void handleData(InputStream inputStream, String contentType) { + try { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + final int BUFFER_SIZE = 8192; + byte[] buffer = new byte[BUFFER_SIZE]; + + for (;;) { + int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE); + + if (bytesRead <= 0) { + break; + } + os.write(buffer, 0, bytesRead); + } + + PluginResult result; + switch (resultType) { + case PluginResult.MESSAGE_TYPE_STRING: + result = new PluginResult(PluginResult.Status.OK, os.toString(encoding)); + break; + case PluginResult.MESSAGE_TYPE_ARRAYBUFFER: + result = new PluginResult(PluginResult.Status.OK, os.toByteArray()); + break; + case PluginResult.MESSAGE_TYPE_BINARYSTRING: + result = new PluginResult(PluginResult.Status.OK, os.toByteArray(), true); + break; + default: // Base64. + byte[] base64 = Base64.encode(os.toByteArray(), Base64.NO_WRAP); + String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII"); + result = new PluginResult(PluginResult.Status.OK, s); + } + + callbackContext.sendPluginResult(result); + } catch (IOException e) { + LOG.d(LOG_TAG, e.getLocalizedMessage()); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR)); + } + } + }); + + + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } catch (FileNotFoundException e) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_FOUND_ERR)); + } catch (IOException e) { + LOG.d(LOG_TAG, e.getLocalizedMessage()); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR)); + } + } + + + /** + * Write contents of file. + * + * @param data The contents of the file. + * @param offset The position to begin writing the file. + * @param isBinary True if the file contents are base64-encoded binary data + */ + /**/ + public long write(String srcURLstr, String data, int offset, boolean isBinary) throws FileNotFoundException, IOException, NoModificationAllowedException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + + long x = fs.writeToFileAtURL(inputURL, data, offset, isBinary); LOG.d("TEST",srcURLstr + ": "+x); return x; + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + + } + + /** + * Truncate the file to size + */ + private long truncateFile(String srcURLstr, long size) throws FileNotFoundException, IOException, NoModificationAllowedException { + try { + LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr); + Filesystem fs = this.filesystemForURL(inputURL); + if (fs == null) { + throw new MalformedURLException("No installed handlers for this URL"); + } + + return fs.truncateFileAtURL(inputURL, size); + } catch (IllegalArgumentException e) { + MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL"); + mue.initCause(e); + throw mue; + } + } + + + /* + * Handle the response + */ + + public void onRequestPermissionResult(int requestCode, String[] permissions, + int[] grantResults) throws JSONException { + + final PendingRequests.Request req = pendingRequests.getAndRemove(requestCode); + if (req != null) { + for(int r:grantResults) + { + if(r == PackageManager.PERMISSION_DENIED) + { + req.getCallbackContext().sendPluginResult(new PluginResult(PluginResult.Status.ERROR, SECURITY_ERR)); + return; + } + } + switch(req.getAction()) + { + case ACTION_GET_FILE: + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException { + String dirname = args.getString(0); + + String path = args.getString(1); + JSONObject obj = getFile(dirname, path, args.optJSONObject(2), false); + req.getCallbackContext().success(obj); + } + }, req.getRawArgs(), req.getCallbackContext()); + break; + case ACTION_GET_DIRECTORY: + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException { + String dirname = args.getString(0); + + String path = args.getString(1); + JSONObject obj = getFile(dirname, path, args.optJSONObject(2), true); + req.getCallbackContext().success(obj); + } + }, req.getRawArgs(), req.getCallbackContext()); + break; + case ACTION_WRITE: + threadhelper( new FileOp( ){ + public void run(JSONArray args) throws JSONException, FileNotFoundException, IOException, NoModificationAllowedException { + String fname=args.getString(0); + String data=args.getString(1); + int offset=args.getInt(2); + Boolean isBinary=args.getBoolean(3); + long fileSize = write(fname, data, offset, isBinary); + req.getCallbackContext().sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize)); + } + }, req.getRawArgs(), req.getCallbackContext()); + break; + } + } else { + LOG.d(LOG_TAG, "Received permission callback for unknown request code"); + } + } +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/Filesystem.java b/mobile/plugins/cordova-plugin-file/src/android/Filesystem.java new file mode 100644 index 0000000..c69d3bd --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/Filesystem.java @@ -0,0 +1,331 @@ +/* + 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.cordova.file; + +import android.net.Uri; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; + +import org.apache.cordova.CordovaResourceApi; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public abstract class Filesystem { + + protected final Uri rootUri; + protected final CordovaResourceApi resourceApi; + public final String name; + private JSONObject rootEntry; + + public Filesystem(Uri rootUri, String name, CordovaResourceApi resourceApi) { + this.rootUri = rootUri; + this.name = name; + this.resourceApi = resourceApi; + } + + public interface ReadFileCallback { + public void handleData(InputStream inputStream, String contentType) throws IOException; + } + + public static JSONObject makeEntryForURL(LocalFilesystemURL inputURL, Uri nativeURL) { + try { + String path = inputURL.path; + int end = path.endsWith("/") ? 1 : 0; + String[] parts = path.substring(0, path.length() - end).split("/+"); + String fileName = parts[parts.length - 1]; + + JSONObject entry = new JSONObject(); + entry.put("isFile", !inputURL.isDirectory); + entry.put("isDirectory", inputURL.isDirectory); + entry.put("name", fileName); + entry.put("fullPath", path); + // The file system can't be specified, as it would lead to an infinite loop, + // but the filesystem name can be. + entry.put("filesystemName", inputURL.fsName); + // Backwards compatibility + entry.put("filesystem", "temporary".equals(inputURL.fsName) ? 0 : 1); + + String nativeUrlStr = nativeURL.toString(); + if (inputURL.isDirectory && !nativeUrlStr.endsWith("/")) { + nativeUrlStr += "/"; + } + entry.put("nativeURL", nativeUrlStr); + return entry; + } catch (JSONException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public JSONObject makeEntryForURL(LocalFilesystemURL inputURL) { + Uri nativeUri = toNativeUri(inputURL); + return nativeUri == null ? null : makeEntryForURL(inputURL, nativeUri); + } + + public JSONObject makeEntryForNativeUri(Uri nativeUri) { + LocalFilesystemURL inputUrl = toLocalUri(nativeUri); + return inputUrl == null ? null : makeEntryForURL(inputUrl, nativeUri); + } + + public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException { + return makeEntryForURL(inputURL); + } + + public JSONObject makeEntryForFile(File file) { + return makeEntryForNativeUri(Uri.fromFile(file)); + } + + abstract JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, String path, + JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException; + + abstract boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException, NoModificationAllowedException; + + abstract boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException, NoModificationAllowedException; + + abstract LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException; + + public final JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException { + LocalFilesystemURL[] children = listChildren(inputURL); + JSONArray entries = new JSONArray(); + if (children != null) { + for (LocalFilesystemURL url : children) { + entries.put(makeEntryForURL(url)); + } + } + return entries; + } + + abstract JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException; + + public Uri getRootUri() { + return rootUri; + } + + public boolean exists(LocalFilesystemURL inputURL) { + try { + getFileMetadataForLocalURL(inputURL); + } catch (FileNotFoundException e) { + return false; + } + return true; + } + + public Uri nativeUriForFullPath(String fullPath) { + Uri ret = null; + if (fullPath != null) { + String encodedPath = Uri.fromFile(new File(fullPath)).getEncodedPath(); + if (encodedPath.startsWith("/")) { + encodedPath = encodedPath.substring(1); + } + ret = rootUri.buildUpon().appendEncodedPath(encodedPath).build(); + } + return ret; + } + + public LocalFilesystemURL localUrlforFullPath(String fullPath) { + Uri nativeUri = nativeUriForFullPath(fullPath); + if (nativeUri != null) { + return toLocalUri(nativeUri); + } + return null; + } + + /** + * Removes multiple repeated //s, and collapses processes ../s. + */ + protected static String normalizePath(String rawPath) { + // If this is an absolute path, trim the leading "/" and replace it later + boolean isAbsolutePath = rawPath.startsWith("/"); + if (isAbsolutePath) { + rawPath = rawPath.replaceFirst("/+", ""); + } + ArrayList components = new ArrayList(Arrays.asList(rawPath.split("/+"))); + for (int index = 0; index < components.size(); ++index) { + if (components.get(index).equals("..")) { + components.remove(index); + if (index > 0) { + components.remove(index-1); + --index; + } + } + } + StringBuilder normalizedPath = new StringBuilder(); + for(String component: components) { + normalizedPath.append("/"); + normalizedPath.append(component); + } + if (isAbsolutePath) { + return normalizedPath.toString(); + } else { + return normalizedPath.toString().substring(1); + } + } + + /** + * Gets the free space in bytes available on this filesystem. + * Subclasses may override this method to return nonzero free space. + */ + public long getFreeSpaceInBytes() { + return 0; + } + + public abstract Uri toNativeUri(LocalFilesystemURL inputURL); + public abstract LocalFilesystemURL toLocalUri(Uri inputURL); + + public JSONObject getRootEntry() { + if (rootEntry == null) { + rootEntry = makeEntryForNativeUri(rootUri); + } + return rootEntry; + } + + public JSONObject getParentForLocalURL(LocalFilesystemURL inputURL) throws IOException { + Uri parentUri = inputURL.uri; + String parentPath = new File(inputURL.uri.getPath()).getParent(); + if (!"/".equals(parentPath)) { + parentUri = inputURL.uri.buildUpon().path(parentPath + '/').build(); + } + return getEntryForLocalURL(LocalFilesystemURL.parse(parentUri)); + } + + protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL, LocalFilesystemURL destURL, boolean isDirectory) { + // I know this looks weird but it is to work around a JSON bug. + if ("null".equals(newName) || "".equals(newName)) { + newName = srcURL.uri.getLastPathSegment();; + } + + String newDest = destURL.uri.toString(); + if (newDest.endsWith("/")) { + newDest = newDest + newName; + } else { + newDest = newDest + "/" + newName; + } + if (isDirectory) { + newDest += '/'; + } + return LocalFilesystemURL.parse(newDest); + } + + /* Read a source URL (possibly from a different filesystem, srcFs,) and copy it to + * the destination URL on this filesystem, optionally with a new filename. + * If move is true, then this method should either perform an atomic move operation + * or remove the source file when finished. + */ + public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName, + Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException { + // First, check to see that we can do it + if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) { + throw new NoModificationAllowedException("Cannot move file at source URL"); + } + final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory); + + Uri srcNativeUri = srcFs.toNativeUri(srcURL); + + CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(srcNativeUri); + OutputStream os = null; + try { + os = getOutputStreamForURL(destination); + } catch (IOException e) { + ofrr.inputStream.close(); + throw e; + } + // Closes streams. + resourceApi.copyResource(ofrr, os); + + if (move) { + srcFs.removeFileAtLocalURL(srcURL); + } + return getEntryForLocalURL(destination); + } + + public OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL) throws IOException { + return resourceApi.openOutputStream(toNativeUri(inputURL)); + } + + public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end, + ReadFileCallback readFileCallback) throws IOException { + CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(toNativeUri(inputURL)); + if (end < 0) { + end = ofrr.length; + } + long numBytesToRead = end - start; + try { + if (start > 0) { + ofrr.inputStream.skip(start); + } + InputStream inputStream = ofrr.inputStream; + if (end < ofrr.length) { + inputStream = new LimitedInputStream(inputStream, numBytesToRead); + } + readFileCallback.handleData(inputStream, ofrr.mimeType); + } finally { + ofrr.inputStream.close(); + } + } + + abstract long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset, + boolean isBinary) throws NoModificationAllowedException, IOException; + + abstract long truncateFileAtURL(LocalFilesystemURL inputURL, long size) + throws IOException, NoModificationAllowedException; + + // This method should return null if filesystem urls cannot be mapped to paths + abstract String filesystemPathForURL(LocalFilesystemURL url); + + abstract LocalFilesystemURL URLforFilesystemPath(String path); + + abstract boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL); + + protected class LimitedInputStream extends FilterInputStream { + long numBytesToRead; + public LimitedInputStream(InputStream in, long numBytesToRead) { + super(in); + this.numBytesToRead = numBytesToRead; + } + @Override + public int read() throws IOException { + if (numBytesToRead <= 0) { + return -1; + } + numBytesToRead--; + return in.read(); + } + @Override + public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { + if (numBytesToRead <= 0) { + return -1; + } + int bytesToRead = byteCount; + if (byteCount > numBytesToRead) { + bytesToRead = (int)numBytesToRead; // Cast okay; long is less than int here. + } + int numBytesRead = in.read(buffer, byteOffset, bytesToRead); + numBytesToRead -= numBytesRead; + return numBytesRead; + } + } +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/InvalidModificationException.java b/mobile/plugins/cordova-plugin-file/src/android/InvalidModificationException.java new file mode 100644 index 0000000..8f6bec5 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/InvalidModificationException.java @@ -0,0 +1,30 @@ +/* + 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.cordova.file; + +@SuppressWarnings("serial") +public class InvalidModificationException extends Exception { + + public InvalidModificationException(String message) { + super(message); + } + +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/LocalFilesystem.java b/mobile/plugins/cordova-plugin-file/src/android/LocalFilesystem.java new file mode 100644 index 0000000..051f994 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/LocalFilesystem.java @@ -0,0 +1,513 @@ +/* + 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.cordova.file; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import org.apache.cordova.CordovaResourceApi; +import org.json.JSONException; +import org.json.JSONObject; + +import android.os.Build; +import android.os.Environment; +import android.util.Base64; +import android.net.Uri; +import android.content.Context; +import android.content.Intent; + +import java.nio.charset.Charset; + +public class LocalFilesystem extends Filesystem { + private final Context context; + + public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, File fsRoot) { + super(Uri.fromFile(fsRoot).buildUpon().appendEncodedPath("").build(), name, resourceApi); + this.context = context; + } + + public String filesystemPathForFullPath(String fullPath) { + return new File(rootUri.getPath(), fullPath).toString(); + } + + @Override + public String filesystemPathForURL(LocalFilesystemURL url) { + return filesystemPathForFullPath(url.path); + } + + private String fullPathForFilesystemPath(String absolutePath) { + if (absolutePath != null && absolutePath.startsWith(rootUri.getPath())) { + return absolutePath.substring(rootUri.getPath().length() - 1); + } + return null; + } + + @Override + public Uri toNativeUri(LocalFilesystemURL inputURL) { + return nativeUriForFullPath(inputURL.path); + } + + @Override + public LocalFilesystemURL toLocalUri(Uri inputURL) { + if (!"file".equals(inputURL.getScheme())) { + return null; + } + File f = new File(inputURL.getPath()); + // Removes and duplicate /s (e.g. file:///a//b/c) + Uri resolvedUri = Uri.fromFile(f); + String rootUriNoTrailingSlash = rootUri.getEncodedPath(); + rootUriNoTrailingSlash = rootUriNoTrailingSlash.substring(0, rootUriNoTrailingSlash.length() - 1); + if (!resolvedUri.getEncodedPath().startsWith(rootUriNoTrailingSlash)) { + return null; + } + String subPath = resolvedUri.getEncodedPath().substring(rootUriNoTrailingSlash.length()); + // Strip leading slash + if (!subPath.isEmpty()) { + subPath = subPath.substring(1); + } + Uri.Builder b = new Uri.Builder() + .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL) + .authority("localhost") + .path(name); + if (!subPath.isEmpty()) { + b.appendEncodedPath(subPath); + } + if (f.isDirectory()) { + // Add trailing / for directories. + b.appendEncodedPath(""); + } + return LocalFilesystemURL.parse(b.build()); + } + + @Override + public LocalFilesystemURL URLforFilesystemPath(String path) { + return localUrlforFullPath(fullPathForFilesystemPath(path)); + } + + @Override + public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, + String path, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException { + boolean create = false; + boolean exclusive = false; + + if (options != null) { + create = options.optBoolean("create"); + if (create) { + exclusive = options.optBoolean("exclusive"); + } + } + + // Check for a ":" character in the file to line up with BB and iOS + if (path.contains(":")) { + throw new EncodingException("This path has an invalid \":\" in it."); + } + + LocalFilesystemURL requestedURL; + + // Check whether the supplied path is absolute or relative + if (directory && !path.endsWith("/")) { + path += "/"; + } + if (path.startsWith("/")) { + requestedURL = localUrlforFullPath(normalizePath(path)); + } else { + requestedURL = localUrlforFullPath(normalizePath(inputURL.path + "/" + path)); + } + + File fp = new File(this.filesystemPathForURL(requestedURL)); + + if (create) { + if (exclusive && fp.exists()) { + throw new FileExistsException("create/exclusive fails"); + } + if (directory) { + fp.mkdir(); + } else { + fp.createNewFile(); + } + if (!fp.exists()) { + throw new FileExistsException("create fails"); + } + } + else { + if (!fp.exists()) { + throw new FileNotFoundException("path does not exist"); + } + if (directory) { + if (fp.isFile()) { + throw new TypeMismatchException("path doesn't exist or is file"); + } + } else { + if (fp.isDirectory()) { + throw new TypeMismatchException("path doesn't exist or is directory"); + } + } + } + + // Return the directory + return makeEntryForURL(requestedURL); + } + + @Override + public boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException { + + File fp = new File(filesystemPathForURL(inputURL)); + + // You can't delete a directory that is not empty + if (fp.isDirectory() && fp.list().length > 0) { + throw new InvalidModificationException("You can't delete a directory that is not empty."); + } + + return fp.delete(); + } + + @Override + public boolean exists(LocalFilesystemURL inputURL) { + File fp = new File(filesystemPathForURL(inputURL)); + return fp.exists(); + } + + @Override + public long getFreeSpaceInBytes() { + return DirectoryManager.getFreeSpaceInBytes(rootUri.getPath()); + } + + @Override + public boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException { + File directory = new File(filesystemPathForURL(inputURL)); + return removeDirRecursively(directory); + } + + protected boolean removeDirRecursively(File directory) throws FileExistsException { + if (directory.isDirectory()) { + for (File file : directory.listFiles()) { + removeDirRecursively(file); + } + } + + if (!directory.delete()) { + throw new FileExistsException("could not delete: " + directory.getName()); + } else { + return true; + } + } + + @Override + public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException { + File fp = new File(filesystemPathForURL(inputURL)); + + if (!fp.exists()) { + // The directory we are listing doesn't exist so we should fail. + throw new FileNotFoundException(); + } + + File[] files = fp.listFiles(); + if (files == null) { + // inputURL is a directory + return null; + } + LocalFilesystemURL[] entries = new LocalFilesystemURL[files.length]; + for (int i = 0; i < files.length; i++) { + entries[i] = URLforFilesystemPath(files[i].getPath()); + } + + return entries; + } + + @Override + public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException { + File file = new File(filesystemPathForURL(inputURL)); + + if (!file.exists()) { + throw new FileNotFoundException("File at " + inputURL.uri + " does not exist."); + } + + JSONObject metadata = new JSONObject(); + try { + // Ensure that directories report a size of 0 + metadata.put("size", file.isDirectory() ? 0 : file.length()); + metadata.put("type", resourceApi.getMimeType(Uri.fromFile(file))); + metadata.put("name", file.getName()); + metadata.put("fullPath", inputURL.path); + metadata.put("lastModifiedDate", file.lastModified()); + } catch (JSONException e) { + return null; + } + return metadata; + } + + private void copyFile(Filesystem srcFs, LocalFilesystemURL srcURL, File destFile, boolean move) throws IOException, InvalidModificationException, NoModificationAllowedException { + if (move) { + String realSrcPath = srcFs.filesystemPathForURL(srcURL); + if (realSrcPath != null) { + File srcFile = new File(realSrcPath); + if (srcFile.renameTo(destFile)) { + return; + } + // Trying to rename the file failed. Possibly because we moved across file system on the device. + } + } + + CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(srcFs.toNativeUri(srcURL)); + copyResource(offr, new FileOutputStream(destFile)); + + if (move) { + srcFs.removeFileAtLocalURL(srcURL); + } + } + + private void copyDirectory(Filesystem srcFs, LocalFilesystemURL srcURL, File dstDir, boolean move) throws IOException, NoModificationAllowedException, InvalidModificationException, FileExistsException { + if (move) { + String realSrcPath = srcFs.filesystemPathForURL(srcURL); + if (realSrcPath != null) { + File srcDir = new File(realSrcPath); + // If the destination directory already exists and is empty then delete it. This is according to spec. + if (dstDir.exists()) { + if (dstDir.list().length > 0) { + throw new InvalidModificationException("directory is not empty"); + } + dstDir.delete(); + } + // Try to rename the directory + if (srcDir.renameTo(dstDir)) { + return; + } + // Trying to rename the file failed. Possibly because we moved across file system on the device. + } + } + + if (dstDir.exists()) { + if (dstDir.list().length > 0) { + throw new InvalidModificationException("directory is not empty"); + } + } else { + if (!dstDir.mkdir()) { + // If we can't create the directory then fail + throw new NoModificationAllowedException("Couldn't create the destination directory"); + } + } + + LocalFilesystemURL[] children = srcFs.listChildren(srcURL); + for (LocalFilesystemURL childLocalUrl : children) { + File target = new File(dstDir, new File(childLocalUrl.path).getName()); + if (childLocalUrl.isDirectory) { + copyDirectory(srcFs, childLocalUrl, target, false); + } else { + copyFile(srcFs, childLocalUrl, target, false); + } + } + + if (move) { + srcFs.recursiveRemoveFileAtLocalURL(srcURL); + } + } + + @Override + public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName, + Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException { + + // Check to see if the destination directory exists + String newParent = this.filesystemPathForURL(destURL); + File destinationDir = new File(newParent); + if (!destinationDir.exists()) { + // The destination does not exist so we should fail. + throw new FileNotFoundException("The source does not exist"); + } + + // Figure out where we should be copying to + final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory); + + Uri dstNativeUri = toNativeUri(destinationURL); + Uri srcNativeUri = srcFs.toNativeUri(srcURL); + // Check to see if source and destination are the same file + if (dstNativeUri.equals(srcNativeUri)) { + throw new InvalidModificationException("Can't copy onto itself"); + } + + if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) { + throw new InvalidModificationException("Source URL is read-only (cannot move)"); + } + + File destFile = new File(dstNativeUri.getPath()); + if (destFile.exists()) { + if (!srcURL.isDirectory && destFile.isDirectory()) { + throw new InvalidModificationException("Can't copy/move a file to an existing directory"); + } else if (srcURL.isDirectory && destFile.isFile()) { + throw new InvalidModificationException("Can't copy/move a directory to an existing file"); + } + } + + if (srcURL.isDirectory) { + // E.g. Copy /sdcard/myDir to /sdcard/myDir/backup + if (dstNativeUri.toString().startsWith(srcNativeUri.toString() + '/')) { + throw new InvalidModificationException("Can't copy directory into itself"); + } + copyDirectory(srcFs, srcURL, destFile, move); + } else { + copyFile(srcFs, srcURL, destFile, move); + } + return makeEntryForURL(destinationURL); + } + + @Override + public long writeToFileAtURL(LocalFilesystemURL inputURL, String data, + int offset, boolean isBinary) throws IOException, NoModificationAllowedException { + + boolean append = false; + if (offset > 0) { + this.truncateFileAtURL(inputURL, offset); + append = true; + } + + byte[] rawData; + if (isBinary) { + rawData = Base64.decode(data, Base64.DEFAULT); + } else { + rawData = data.getBytes(Charset.defaultCharset()); + } + ByteArrayInputStream in = new ByteArrayInputStream(rawData); + try + { + byte buff[] = new byte[rawData.length]; + String absolutePath = filesystemPathForURL(inputURL); + FileOutputStream out = new FileOutputStream(absolutePath, append); + try { + in.read(buff, 0, buff.length); + out.write(buff, 0, rawData.length); + out.flush(); + } finally { + // Always close the output + out.close(); + } + if (isPublicDirectory(absolutePath)) { + broadcastNewFile(Uri.fromFile(new File(absolutePath))); + } + } + catch (NullPointerException e) + { + // This is a bug in the Android implementation of the Java Stack + NoModificationAllowedException realException = new NoModificationAllowedException(inputURL.toString()); + realException.initCause(e); + throw realException; + } + + return rawData.length; + } + + private boolean isPublicDirectory(String absolutePath) { + // TODO: should expose a way to scan app's private files (maybe via a flag). + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // Lollipop has a bug where SD cards are null. + for (File f : context.getExternalMediaDirs()) { + if(f != null && absolutePath.startsWith(f.getAbsolutePath())) { + return true; + } + } + } + + String extPath = Environment.getExternalStorageDirectory().getAbsolutePath(); + return absolutePath.startsWith(extPath); + } + + /** + * Send broadcast of new file so files appear over MTP + */ + private void broadcastNewFile(Uri nativeUri) { + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, nativeUri); + context.sendBroadcast(intent); + } + + @Override + public long truncateFileAtURL(LocalFilesystemURL inputURL, long size) throws IOException { + File file = new File(filesystemPathForURL(inputURL)); + + if (!file.exists()) { + throw new FileNotFoundException("File at " + inputURL.uri + " does not exist."); + } + + RandomAccessFile raf = new RandomAccessFile(filesystemPathForURL(inputURL), "rw"); + try { + if (raf.length() >= size) { + FileChannel channel = raf.getChannel(); + channel.truncate(size); + return size; + } + + return raf.length(); + } finally { + raf.close(); + } + + + } + + @Override + public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) { + String path = filesystemPathForURL(inputURL); + File file = new File(path); + return file.exists(); + } + + // This is a copy & paste from CordovaResource API that is required since CordovaResourceApi + // has a bug pre-4.0.0. + // TODO: Once cordova-android@4.0.0 is released, delete this copy and make the plugin depend on + // 4.0.0 with an engine tag. + private static void copyResource(CordovaResourceApi.OpenForReadResult input, OutputStream outputStream) throws IOException { + try { + InputStream inputStream = input.inputStream; + if (inputStream instanceof FileInputStream && outputStream instanceof FileOutputStream) { + FileChannel inChannel = ((FileInputStream)input.inputStream).getChannel(); + FileChannel outChannel = ((FileOutputStream)outputStream).getChannel(); + long offset = 0; + long length = input.length; + if (input.assetFd != null) { + offset = input.assetFd.getStartOffset(); + } + // transferFrom()'s 2nd arg is a relative position. Need to set the absolute + // position first. + inChannel.position(offset); + outChannel.transferFrom(inChannel, 0, length); + } else { + final int BUFFER_SIZE = 8192; + byte[] buffer = new byte[BUFFER_SIZE]; + + for (;;) { + int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE); + + if (bytesRead <= 0) { + break; + } + outputStream.write(buffer, 0, bytesRead); + } + } + } finally { + input.inputStream.close(); + if (outputStream != null) { + outputStream.close(); + } + } + } +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/LocalFilesystemURL.java b/mobile/plugins/cordova-plugin-file/src/android/LocalFilesystemURL.java new file mode 100644 index 0000000..b96b6ee --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/LocalFilesystemURL.java @@ -0,0 +1,64 @@ +/* + 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.cordova.file; + +import android.net.Uri; + +public class LocalFilesystemURL { + + public static final String FILESYSTEM_PROTOCOL = "cdvfile"; + + public final Uri uri; + public final String fsName; + public final String path; + public final boolean isDirectory; + + private LocalFilesystemURL(Uri uri, String fsName, String fsPath, boolean isDirectory) { + this.uri = uri; + this.fsName = fsName; + this.path = fsPath; + this.isDirectory = isDirectory; + } + + public static LocalFilesystemURL parse(Uri uri) { + if (!FILESYSTEM_PROTOCOL.equals(uri.getScheme())) { + return null; + } + String path = uri.getPath(); + if (path.length() < 1) { + return null; + } + int firstSlashIdx = path.indexOf('/', 1); + if (firstSlashIdx < 0) { + return null; + } + String fsName = path.substring(1, firstSlashIdx); + path = path.substring(firstSlashIdx); + boolean isDirectory = path.charAt(path.length() - 1) == '/'; + return new LocalFilesystemURL(uri, fsName, path, isDirectory); + } + + public static LocalFilesystemURL parse(String uri) { + return parse(Uri.parse(uri)); + } + + public String toString() { + return uri.toString(); + } +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/NoModificationAllowedException.java b/mobile/plugins/cordova-plugin-file/src/android/NoModificationAllowedException.java new file mode 100644 index 0000000..627eafb --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/NoModificationAllowedException.java @@ -0,0 +1,29 @@ +/* + 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.cordova.file; + +@SuppressWarnings("serial") +public class NoModificationAllowedException extends Exception { + + public NoModificationAllowedException(String message) { + super(message); + } + +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/PendingRequests.java b/mobile/plugins/cordova-plugin-file/src/android/PendingRequests.java new file mode 100644 index 0000000..4c75f42 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/PendingRequests.java @@ -0,0 +1,94 @@ +/* + 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.cordova.file; + +import android.util.SparseArray; + +import org.apache.cordova.CallbackContext; + +/** + * Holds pending runtime permission requests + */ +class PendingRequests { + private int currentReqId = 0; + private SparseArray requests = new SparseArray(); + + /** + * Creates a request and adds it to the array of pending requests. Each created request gets a + * unique result code for use with requestPermission() + * @param rawArgs The raw arguments passed to the plugin + * @param action The action this request corresponds to (get file, etc.) + * @param callbackContext The CallbackContext for this plugin call + * @return The request code that can be used to retrieve the Request object + */ + public synchronized int createRequest(String rawArgs, int action, CallbackContext callbackContext) { + Request req = new Request(rawArgs, action, callbackContext); + requests.put(req.requestCode, req); + return req.requestCode; + } + + /** + * Gets the request corresponding to this request code and removes it from the pending requests + * @param requestCode The request code for the desired request + * @return The request corresponding to the given request code or null if such a + * request is not found + */ + public synchronized Request getAndRemove(int requestCode) { + Request result = requests.get(requestCode); + requests.remove(requestCode); + return result; + } + + /** + * Holds the options and CallbackContext for a call made to the plugin. + */ + public class Request { + + // Unique int used to identify this request in any Android permission callback + private int requestCode; + + // Action to be performed after permission request result + private int action; + + // Raw arguments passed to plugin + private String rawArgs; + + // The callback context for this plugin request + private CallbackContext callbackContext; + + private Request(String rawArgs, int action, CallbackContext callbackContext) { + this.rawArgs = rawArgs; + this.action = action; + this.callbackContext = callbackContext; + this.requestCode = currentReqId ++; + } + + public int getAction() { + return this.action; + } + + public String getRawArgs() { + return rawArgs; + } + + public CallbackContext getCallbackContext() { + return callbackContext; + } + } +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/TypeMismatchException.java b/mobile/plugins/cordova-plugin-file/src/android/TypeMismatchException.java new file mode 100644 index 0000000..1315f9a --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/TypeMismatchException.java @@ -0,0 +1,30 @@ +/* + 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.cordova.file; + +@SuppressWarnings("serial") +public class TypeMismatchException extends Exception { + + public TypeMismatchException(String message) { + super(message); + } + +} diff --git a/mobile/plugins/cordova-plugin-file/src/android/build-extras.gradle b/mobile/plugins/cordova-plugin-file/src/android/build-extras.gradle new file mode 100644 index 0000000..a0a7844 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/android/build-extras.gradle @@ -0,0 +1,47 @@ +/* + 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. + */ +ext.postBuildExtras = { + def inAssetsDir = file("assets") + def outAssetsDir = inAssetsDir + def outFile = new File(outAssetsDir, "cdvasset.manifest") + + def newTask = task("cdvCreateAssetManifest") << { + def contents = new HashMap() + def sizes = new HashMap() + contents[""] = inAssetsDir.list() + def tree = fileTree(dir: inAssetsDir) + tree.visit { fileDetails -> + if (fileDetails.isDirectory()) { + contents[fileDetails.relativePath.toString()] = fileDetails.file.list() + } else { + sizes[fileDetails.relativePath.toString()] = fileDetails.file.length() + } + } + + outAssetsDir.mkdirs() + outFile.withObjectOutputStream { oos -> + oos.writeObject(contents) + oos.writeObject(sizes) + } + } + newTask.inputs.dir inAssetsDir + newTask.outputs.file outFile + def preBuildTask = tasks["preBuild"] + preBuildTask.dependsOn(newTask) +} diff --git a/mobile/plugins/cordova-plugin-file/src/blackberry10/index.js b/mobile/plugins/cordova-plugin-file/src/blackberry10/index.js new file mode 100644 index 0000000..e995986 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/blackberry10/index.js @@ -0,0 +1,47 @@ +/* + * + * 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. + * +*/ + +/* global PluginResult */ + +module.exports = { + setSandbox : function (success, fail, args, env) { + require("lib/webview").setSandbox(JSON.parse(decodeURIComponent(args[0]))); + new PluginResult(args, env).ok(); + }, + + getHomePath: function (success, fail, args, env) { + var homeDir = window.qnx.webplatform.getApplication().getEnv("HOME"); + new PluginResult(args, env).ok(homeDir); + }, + + requestAllPaths: function (success, fail, args, env) { + var homeDir = 'file://' + window.qnx.webplatform.getApplication().getEnv("HOME").replace('/data', ''), + paths = { + applicationDirectory: homeDir + '/app/native/', + applicationStorageDirectory: homeDir + '/', + dataDirectory: homeDir + '/data/webviews/webfs/persistent/local__0/', + cacheDirectory: homeDir + '/data/webviews/webfs/temporary/local__0/', + externalRootDirectory: 'file:///accounts/1000/removable/sdcard/', + sharedDirectory: homeDir + '/shared/' + }; + success(paths); + } +}; diff --git a/mobile/plugins/cordova-plugin-file/src/browser/FileProxy.js b/mobile/plugins/cordova-plugin-file/src/browser/FileProxy.js new file mode 100644 index 0000000..2d937f4 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/browser/FileProxy.js @@ -0,0 +1,984 @@ +/* + * + * 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. + * + */ +(function() { + /*global require, exports, module*/ + /*global FILESYSTEM_PREFIX*/ + /*global IDBKeyRange*/ + + /* Heavily based on https://github.com/ebidel/idb.filesystem.js */ + + // For chrome we don't need to implement proxy methods + // All functionality can be accessed natively. + if (require('./isChrome')()) { + var pathsPrefix = { + // Read-only directory where the application is installed. + applicationDirectory: location.origin + "/", + // Where to put app-specific data files. + dataDirectory: 'filesystem:file:///persistent/', + // Cached files that should survive app restarts. + // Apps should not rely on the OS to delete files in here. + cacheDirectory: 'filesystem:file:///temporary/', + }; + + exports.requestAllPaths = function(successCallback) { + successCallback(pathsPrefix); + }; + + require("cordova/exec/proxy").add("File", module.exports); + return; + } + + var LocalFileSystem = require('./LocalFileSystem'), + FileSystem = require('./FileSystem'), + FileEntry = require('./FileEntry'), + FileError = require('./FileError'), + DirectoryEntry = require('./DirectoryEntry'), + File = require('./File'); + + (function(exports, global) { + var indexedDB = global.indexedDB || global.mozIndexedDB; + if (!indexedDB) { + throw "Firefox OS File plugin: indexedDB not supported"; + } + + var fs_ = null; + + var idb_ = {}; + idb_.db = null; + var FILE_STORE_ = 'entries'; + + var DIR_SEPARATOR = '/'; + + var pathsPrefix = { + // Read-only directory where the application is installed. + applicationDirectory: location.origin + "/", + // Where to put app-specific data files. + dataDirectory: 'file:///persistent/', + // Cached files that should survive app restarts. + // Apps should not rely on the OS to delete files in here. + cacheDirectory: 'file:///temporary/', + }; + + var unicodeLastChar = 65535; + + /*** Exported functionality ***/ + + exports.requestFileSystem = function(successCallback, errorCallback, args) { + var type = args[0]; + // Size is ignored since IDB filesystem size depends + // on browser implementation and can't be set up by user + var size = args[1]; // jshint ignore: line + + if (type !== LocalFileSystem.TEMPORARY && type !== LocalFileSystem.PERSISTENT) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var name = type === LocalFileSystem.TEMPORARY ? 'temporary' : 'persistent'; + var storageName = (location.protocol + location.host).replace(/:/g, '_'); + + var root = new DirectoryEntry('', DIR_SEPARATOR); + fs_ = new FileSystem(name, root); + + idb_.open(storageName, function() { + successCallback(fs_); + }, errorCallback); + }; + + // Overridden by Android, BlackBerry 10 and iOS to populate fsMap + require('./fileSystems').getFs = function(name, callback) { + callback(new FileSystem(name, fs_.root)); + }; + + // list a directory's contents (files and folders). + exports.readEntries = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + + if (typeof successCallback !== 'function') { + throw Error('Expected successCallback argument.'); + } + + var path = resolveToFullPath_(fullPath); + + exports.getDirectory(function() { + idb_.getAllEntries(path.fullPath + DIR_SEPARATOR, path.storagePath, function(entries) { + successCallback(entries); + }, errorCallback); + }, function() { + if (errorCallback) { + errorCallback(FileError.NOT_FOUND_ERR); + } + }, [path.storagePath, path.fullPath, {create: false}]); + }; + + exports.getFile = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + var path = args[1]; + var options = args[2] || {}; + + // Create an absolute path if we were handed a relative one. + path = resolveToFullPath_(fullPath, path); + + idb_.get(path.storagePath, function(fileEntry) { + if (options.create === true && options.exclusive === true && fileEntry) { + // If create and exclusive are both true, and the path already exists, + // getFile must fail. + + if (errorCallback) { + errorCallback(FileError.PATH_EXISTS_ERR); + } + } else if (options.create === true && !fileEntry) { + // If create is true, the path doesn't exist, and no other error occurs, + // getFile must create it as a zero-length file and return a corresponding + // FileEntry. + var newFileEntry = new FileEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root)); + + newFileEntry.file_ = new MyFile({ + size: 0, + name: newFileEntry.name, + lastModifiedDate: new Date(), + storagePath: path.storagePath + }); + + idb_.put(newFileEntry, path.storagePath, successCallback, errorCallback); + } else if (options.create === true && fileEntry) { + if (fileEntry.isFile) { + // Overwrite file, delete then create new. + idb_['delete'](path.storagePath, function() { + var newFileEntry = new FileEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root)); + + newFileEntry.file_ = new MyFile({ + size: 0, + name: newFileEntry.name, + lastModifiedDate: new Date(), + storagePath: path.storagePath + }); + + idb_.put(newFileEntry, path.storagePath, successCallback, errorCallback); + }, errorCallback); + } else { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + } + } else if ((!options.create || options.create === false) && !fileEntry) { + // If create is not true and the path doesn't exist, getFile must fail. + if (errorCallback) { + errorCallback(FileError.NOT_FOUND_ERR); + } + } else if ((!options.create || options.create === false) && fileEntry && + fileEntry.isDirectory) { + // If create is not true and the path exists, but is a directory, getFile + // must fail. + if (errorCallback) { + errorCallback(FileError.TYPE_MISMATCH_ERR); + } + } else { + // Otherwise, if no other error occurs, getFile must return a FileEntry + // corresponding to path. + + successCallback(fileEntryFromIdbEntry(fileEntry)); + } + }, errorCallback); + }; + + exports.getFileMetadata = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + + exports.getFile(function(fileEntry) { + successCallback(new File(fileEntry.file_.name, fileEntry.fullPath, '', fileEntry.file_.lastModifiedDate, + fileEntry.file_.size)); + }, errorCallback, [fullPath, null]); + }; + + exports.getMetadata = function(successCallback, errorCallback, args) { + exports.getFile(function (fileEntry) { + successCallback( + { + modificationTime: fileEntry.file_.lastModifiedDate, + size: fileEntry.file_.lastModifiedDate + }); + }, errorCallback, args); + }; + + exports.setMetadata = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + var metadataObject = args[1]; + + exports.getFile(function (fileEntry) { + fileEntry.file_.lastModifiedDate = metadataObject.modificationTime; + idb_.put(fileEntry, fileEntry.file_.storagePath, successCallback, errorCallback); + }, errorCallback, [fullPath, null]); + }; + + exports.write = function(successCallback, errorCallback, args) { + var fileName = args[0], + data = args[1], + position = args[2], + isBinary = args[3]; // jshint ignore: line + + if (!data) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + if (typeof data === 'string' || data instanceof String) { + data = new Blob([data]); + } + + exports.getFile(function(fileEntry) { + var blob_ = fileEntry.file_.blob_; + + if (!blob_) { + blob_ = new Blob([data], {type: data.type}); + } else { + // Calc the head and tail fragments + var head = blob_.slice(0, position); + var tail = blob_.slice(position + (data.size || data.byteLength)); + + // Calc the padding + var padding = position - head.size; + if (padding < 0) { + padding = 0; + } + + // Do the "write". In fact, a full overwrite of the Blob. + blob_ = new Blob([head, new Uint8Array(padding), data, tail], + {type: data.type}); + } + + // Set the blob we're writing on this file entry so we can recall it later. + fileEntry.file_.blob_ = blob_; + fileEntry.file_.lastModifiedDate = new Date() || null; + fileEntry.file_.size = blob_.size; + fileEntry.file_.name = blob_.name; + fileEntry.file_.type = blob_.type; + + idb_.put(fileEntry, fileEntry.file_.storagePath, function() { + successCallback(data.size || data.byteLength); + }, errorCallback); + }, errorCallback, [fileName, null]); + }; + + exports.readAsText = function(successCallback, errorCallback, args) { + var fileName = args[0], + enc = args[1], + startPos = args[2], + endPos = args[3]; + + readAs('text', fileName, enc, startPos, endPos, successCallback, errorCallback); + }; + + exports.readAsDataURL = function(successCallback, errorCallback, args) { + var fileName = args[0], + startPos = args[1], + endPos = args[2]; + + readAs('dataURL', fileName, null, startPos, endPos, successCallback, errorCallback); + }; + + exports.readAsBinaryString = function(successCallback, errorCallback, args) { + var fileName = args[0], + startPos = args[1], + endPos = args[2]; + + readAs('binaryString', fileName, null, startPos, endPos, successCallback, errorCallback); + }; + + exports.readAsArrayBuffer = function(successCallback, errorCallback, args) { + var fileName = args[0], + startPos = args[1], + endPos = args[2]; + + readAs('arrayBuffer', fileName, null, startPos, endPos, successCallback, errorCallback); + }; + + exports.removeRecursively = exports.remove = function(successCallback, errorCallback, args) { + if (typeof successCallback !== 'function') { + throw Error('Expected successCallback argument.'); + } + + var fullPath = resolveToFullPath_(args[0]).storagePath; + if (fullPath === pathsPrefix.cacheDirectory || fullPath === pathsPrefix.dataDirectory) { + errorCallback(FileError.NO_MODIFICATION_ALLOWED_ERR); + return; + } + + function deleteEntry(isDirectory) { + // TODO: This doesn't protect against directories that have content in it. + // Should throw an error instead if the dirEntry is not empty. + idb_['delete'](fullPath, function() { + successCallback(); + }, function() { + if (errorCallback) { errorCallback(); } + }, isDirectory); + } + + // We need to to understand what we are deleting: + exports.getDirectory(function(entry) { + deleteEntry(entry.isDirectory); + }, function(){ + //DirectoryEntry was already deleted or entry is FileEntry + deleteEntry(false); + }, [fullPath, null, {create: false}]); + }; + + exports.getDirectory = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + var path = args[1]; + var options = args[2]; + + // Create an absolute path if we were handed a relative one. + path = resolveToFullPath_(fullPath, path); + + idb_.get(path.storagePath, function(folderEntry) { + if (!options) { + options = {}; + } + + if (options.create === true && options.exclusive === true && folderEntry) { + // If create and exclusive are both true, and the path already exists, + // getDirectory must fail. + if (errorCallback) { + errorCallback(FileError.PATH_EXISTS_ERR); + } + // There is a strange bug in mobilespec + FF, which results in coming to multiple else-if's + // so we are shielding from it with returns. + return; + } + + if (options.create === true && !folderEntry) { + // If create is true, the path doesn't exist, and no other error occurs, + // getDirectory must create it as a zero-length file and return a corresponding + // MyDirectoryEntry. + var dirEntry = new DirectoryEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root)); + + idb_.put(dirEntry, path.storagePath, successCallback, errorCallback); + return; + } + + if (options.create === true && folderEntry) { + + if (folderEntry.isDirectory) { + // IDB won't save methods, so we need re-create the MyDirectoryEntry. + successCallback(new DirectoryEntry(folderEntry.name, folderEntry.fullPath, folderEntry.filesystem)); + } else { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + } + return; + } + + if ((!options.create || options.create === false) && !folderEntry) { + // Handle root special. It should always exist. + if (path.fullPath === DIR_SEPARATOR) { + successCallback(fs_.root); + return; + } + + // If create is not true and the path doesn't exist, getDirectory must fail. + if (errorCallback) { + errorCallback(FileError.NOT_FOUND_ERR); + } + + return; + } + if ((!options.create || options.create === false) && folderEntry && folderEntry.isFile) { + // If create is not true and the path exists, but is a file, getDirectory + // must fail. + if (errorCallback) { + errorCallback(FileError.TYPE_MISMATCH_ERR); + } + return; + } + + // Otherwise, if no other error occurs, getDirectory must return a + // MyDirectoryEntry corresponding to path. + + // IDB won't' save methods, so we need re-create MyDirectoryEntry. + successCallback(new DirectoryEntry(folderEntry.name, folderEntry.fullPath, folderEntry.filesystem)); + }, errorCallback); + }; + + exports.getParent = function(successCallback, errorCallback, args) { + if (typeof successCallback !== 'function') { + throw Error('Expected successCallback argument.'); + } + + var fullPath = args[0]; + //fullPath is like this: + //file:///persistent/path/to/file or + //file:///persistent/path/to/directory/ + + if (fullPath === DIR_SEPARATOR || fullPath === pathsPrefix.cacheDirectory || + fullPath === pathsPrefix.dataDirectory) { + successCallback(fs_.root); + return; + } + + //To delete all slashes at the end + while (fullPath[fullPath.length - 1] === '/') { + fullPath = fullPath.substr(0, fullPath.length - 1); + } + + var pathArr = fullPath.split(DIR_SEPARATOR); + pathArr.pop(); + var parentName = pathArr.pop(); + var path = pathArr.join(DIR_SEPARATOR) + DIR_SEPARATOR; + + //To get parent of root files + var joined = path + parentName + DIR_SEPARATOR;//is like this: file:///persistent/ + if (joined === pathsPrefix.cacheDirectory || joined === pathsPrefix.dataDirectory) { + exports.getDirectory(successCallback, errorCallback, [joined, DIR_SEPARATOR, {create: false}]); + return; + } + + exports.getDirectory(successCallback, errorCallback, [path, parentName, {create: false}]); + }; + + exports.copyTo = function(successCallback, errorCallback, args) { + var srcPath = args[0]; + var parentFullPath = args[1]; + var name = args[2]; + + if (name.indexOf('/') !== -1 || srcPath === parentFullPath + name) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + + return; + } + + // Read src file + exports.getFile(function(srcFileEntry) { + + var path = resolveToFullPath_(parentFullPath); + //Check directory + exports.getDirectory(function() { + + // Create dest file + exports.getFile(function(dstFileEntry) { + + exports.write(function() { + successCallback(dstFileEntry); + }, errorCallback, [dstFileEntry.file_.storagePath, srcFileEntry.file_.blob_, 0]); + + }, errorCallback, [parentFullPath, name, {create: true}]); + + }, function() { if (errorCallback) { errorCallback(FileError.NOT_FOUND_ERR); }}, + [path.storagePath, null, {create:false}]); + + }, errorCallback, [srcPath, null]); + }; + + exports.moveTo = function(successCallback, errorCallback, args) { + var srcPath = args[0]; + // parentFullPath and name parameters is ignored because + // args is being passed downstream to exports.copyTo method + var parentFullPath = args[1]; // jshint ignore: line + var name = args[2]; // jshint ignore: line + + exports.copyTo(function (fileEntry) { + + exports.remove(function () { + successCallback(fileEntry); + }, errorCallback, [srcPath]); + + }, errorCallback, args); + }; + + exports.resolveLocalFileSystemURI = function(successCallback, errorCallback, args) { + var path = args[0]; + + // Ignore parameters + if (path.indexOf('?') !== -1) { + path = String(path).split("?")[0]; + } + + // support for encodeURI + if (/\%5/g.test(path) || /\%20/g.test(path)) { + path = decodeURI(path); + } + + if (path.trim()[0] === '/') { + if (errorCallback) { + errorCallback(FileError.ENCODING_ERR); + } + return; + } + + //support for cdvfile + if (path.trim().substr(0,7) === "cdvfile") { + if (path.indexOf("cdvfile://localhost") === -1) { + if (errorCallback) { + errorCallback(FileError.ENCODING_ERR); + } + return; + } + + var indexPersistent = path.indexOf("persistent"); + var indexTemporary = path.indexOf("temporary"); + + //cdvfile://localhost/persistent/path/to/file + if (indexPersistent !== -1) { + path = "file:///persistent" + path.substr(indexPersistent + 10); + } else if (indexTemporary !== -1) { + path = "file:///temporary" + path.substr(indexTemporary + 9); + } else { + if (errorCallback) { + errorCallback(FileError.ENCODING_ERR); + } + return; + } + } + + // to avoid path form of '///path/to/file' + function handlePathSlashes(path) { + var cutIndex = 0; + for (var i = 0; i < path.length - 1; i++) { + if (path[i] === DIR_SEPARATOR && path[i + 1] === DIR_SEPARATOR) { + cutIndex = i + 1; + } else break; + } + + return path.substr(cutIndex); + } + + // Handle localhost containing paths (see specs ) + if (path.indexOf('file://localhost/') === 0) { + path = path.replace('file://localhost/', 'file:///'); + } + + if (path.indexOf(pathsPrefix.dataDirectory) === 0) { + path = path.substring(pathsPrefix.dataDirectory.length - 1); + path = handlePathSlashes(path); + + exports.requestFileSystem(function() { + exports.getFile(successCallback, function() { + exports.getDirectory(successCallback, errorCallback, [pathsPrefix.dataDirectory, path, + {create: false}]); + }, [pathsPrefix.dataDirectory, path, {create: false}]); + }, errorCallback, [LocalFileSystem.PERSISTENT]); + } else if (path.indexOf(pathsPrefix.cacheDirectory) === 0) { + path = path.substring(pathsPrefix.cacheDirectory.length - 1); + path = handlePathSlashes(path); + + exports.requestFileSystem(function() { + exports.getFile(successCallback, function() { + exports.getDirectory(successCallback, errorCallback, [pathsPrefix.cacheDirectory, path, + {create: false}]); + }, [pathsPrefix.cacheDirectory, path, {create: false}]); + }, errorCallback, [LocalFileSystem.TEMPORARY]); + } else if (path.indexOf(pathsPrefix.applicationDirectory) === 0) { + path = path.substring(pathsPrefix.applicationDirectory.length); + //TODO: need to cut out redundant slashes? + + var xhr = new XMLHttpRequest(); + xhr.open("GET", path, true); + xhr.onreadystatechange = function () { + if (xhr.status === 200 && xhr.readyState === 4) { + exports.requestFileSystem(function(fs) { + fs.name = location.hostname; + + //TODO: need to call exports.getFile(...) to handle errors correct + fs.root.getFile(path, {create: true}, writeFile, errorCallback); + }, errorCallback, [LocalFileSystem.PERSISTENT]); + } + }; + + xhr.onerror = function () { + if(errorCallback) { + errorCallback(FileError.NOT_READABLE_ERR); + } + }; + + xhr.send(); + } else { + if(errorCallback) { + errorCallback(FileError.NOT_FOUND_ERR); + } + } + + function writeFile(entry) { + entry.createWriter(function (fileWriter) { + fileWriter.onwriteend = function (evt) { + if (!evt.target.error) { + entry.filesystemName = location.hostname; + successCallback(entry); + } + }; + fileWriter.onerror = function () { + if (errorCallback) { + errorCallback(FileError.NOT_READABLE_ERR); + } + }; + fileWriter.write(new Blob([xhr.response])); + }, errorCallback); + } + }; + + exports.requestAllPaths = function(successCallback) { + successCallback(pathsPrefix); + }; + + /*** Helpers ***/ + + /** + * Interface to wrap the native File interface. + * + * This interface is necessary for creating zero-length (empty) files, + * something the Filesystem API allows you to do. Unfortunately, File's + * constructor cannot be called directly, making it impossible to instantiate + * an empty File in JS. + * + * @param {Object} opts Initial values. + * @constructor + */ + function MyFile(opts) { + var blob_ = new Blob(); + + this.size = opts.size || 0; + this.name = opts.name || ''; + this.type = opts.type || ''; + this.lastModifiedDate = opts.lastModifiedDate || null; + this.storagePath = opts.storagePath || ''; + + // Need some black magic to correct the object's size/name/type based on the + // blob that is saved. + Object.defineProperty(this, 'blob_', { + enumerable: true, + get: function() { + return blob_; + }, + set: function(val) { + blob_ = val; + this.size = blob_.size; + this.name = blob_.name; + this.type = blob_.type; + this.lastModifiedDate = blob_.lastModifiedDate; + }.bind(this) + }); + } + + MyFile.prototype.constructor = MyFile; + + // When saving an entry, the fullPath should always lead with a slash and never + // end with one (e.g. a directory). Also, resolve '.' and '..' to an absolute + // one. This method ensures path is legit! + function resolveToFullPath_(cwdFullPath, path) { + path = path || ''; + var fullPath = path; + var prefix = ''; + + cwdFullPath = cwdFullPath || DIR_SEPARATOR; + if (cwdFullPath.indexOf(FILESYSTEM_PREFIX) === 0) { + prefix = cwdFullPath.substring(0, cwdFullPath.indexOf(DIR_SEPARATOR, FILESYSTEM_PREFIX.length)); + cwdFullPath = cwdFullPath.substring(cwdFullPath.indexOf(DIR_SEPARATOR, FILESYSTEM_PREFIX.length)); + } + + var relativePath = path[0] !== DIR_SEPARATOR; + if (relativePath) { + fullPath = cwdFullPath; + if (cwdFullPath !== DIR_SEPARATOR) { + fullPath += DIR_SEPARATOR + path; + } else { + fullPath += path; + } + } + + // Remove doubled separator substrings + var re = new RegExp(DIR_SEPARATOR + DIR_SEPARATOR, 'g'); + fullPath = fullPath.replace(re, DIR_SEPARATOR); + + // Adjust '..'s by removing parent directories when '..' flows in path. + var parts = fullPath.split(DIR_SEPARATOR); + for (var i = 0; i < parts.length; ++i) { + var part = parts[i]; + if (part === '..') { + parts[i - 1] = ''; + parts[i] = ''; + } + } + fullPath = parts.filter(function(el) { + return el; + }).join(DIR_SEPARATOR); + + // Add back in leading slash. + if (fullPath[0] !== DIR_SEPARATOR) { + fullPath = DIR_SEPARATOR + fullPath; + } + + // Replace './' by current dir. ('./one/./two' -> one/two) + fullPath = fullPath.replace(/\.\//g, DIR_SEPARATOR); + + // Replace '//' with '/'. + fullPath = fullPath.replace(/\/\//g, DIR_SEPARATOR); + + // Replace '/.' with '/'. + fullPath = fullPath.replace(/\/\./g, DIR_SEPARATOR); + + // Remove '/' if it appears on the end. + if (fullPath[fullPath.length - 1] === DIR_SEPARATOR && + fullPath !== DIR_SEPARATOR) { + fullPath = fullPath.substring(0, fullPath.length - 1); + } + + var storagePath = prefix + fullPath; + storagePath = decodeURI(storagePath); + fullPath = decodeURI(fullPath); + + return { + storagePath: storagePath, + fullPath: fullPath, + fileName: fullPath.split(DIR_SEPARATOR).pop(), + fsName: prefix.split(DIR_SEPARATOR).pop() + }; + } + + function fileEntryFromIdbEntry(fileEntry) { + // IDB won't save methods, so we need re-create the FileEntry. + var clonedFileEntry = new FileEntry(fileEntry.name, fileEntry.fullPath, fileEntry.filesystem); + clonedFileEntry.file_ = fileEntry.file_; + + return clonedFileEntry; + } + + function readAs(what, fullPath, encoding, startPos, endPos, successCallback, errorCallback) { + exports.getFile(function(fileEntry) { + var fileReader = new FileReader(), + blob = fileEntry.file_.blob_.slice(startPos, endPos); + + fileReader.onload = function(e) { + successCallback(e.target.result); + }; + + fileReader.onerror = errorCallback; + + switch (what) { + case 'text': + fileReader.readAsText(blob, encoding); + break; + case 'dataURL': + fileReader.readAsDataURL(blob); + break; + case 'arrayBuffer': + fileReader.readAsArrayBuffer(blob); + break; + case 'binaryString': + fileReader.readAsBinaryString(blob); + break; + } + + }, errorCallback, [fullPath, null]); + } + + /*** Core logic to handle IDB operations ***/ + + idb_.open = function(dbName, successCallback, errorCallback) { + var self = this; + + // TODO: FF 12.0a1 isn't liking a db name with : in it. + var request = indexedDB.open(dbName.replace(':', '_')/*, 1 /*version*/); + + request.onerror = errorCallback || onError; + + request.onupgradeneeded = function(e) { + // First open was called or higher db version was used. + + // console.log('onupgradeneeded: oldVersion:' + e.oldVersion, + // 'newVersion:' + e.newVersion); + + self.db = e.target.result; + self.db.onerror = onError; + + if (!self.db.objectStoreNames.contains(FILE_STORE_)) { + self.db.createObjectStore(FILE_STORE_/*,{keyPath: 'id', autoIncrement: true}*/); + } + }; + + request.onsuccess = function(e) { + self.db = e.target.result; + self.db.onerror = onError; + successCallback(e); + }; + + request.onblocked = errorCallback || onError; + }; + + idb_.close = function() { + this.db.close(); + this.db = null; + }; + + idb_.get = function(fullPath, successCallback, errorCallback) { + if (!this.db) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var tx = this.db.transaction([FILE_STORE_], 'readonly'); + + var request = tx.objectStore(FILE_STORE_).get(fullPath); + + tx.onabort = errorCallback || onError; + tx.oncomplete = function() { + successCallback(request.result); + }; + }; + + idb_.getAllEntries = function(fullPath, storagePath, successCallback, errorCallback) { + if (!this.db) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var results = []; + + if (storagePath[storagePath.length - 1] === DIR_SEPARATOR) { + storagePath = storagePath.substring(0, storagePath.length - 1); + } + + var range = IDBKeyRange.bound(storagePath + DIR_SEPARATOR + ' ', + storagePath + DIR_SEPARATOR + String.fromCharCode(unicodeLastChar)); + + var tx = this.db.transaction([FILE_STORE_], 'readonly'); + tx.onabort = errorCallback || onError; + tx.oncomplete = function() { + results = results.filter(function(val) { + var pathWithoutSlash = val.fullPath; + + if (val.fullPath[val.fullPath.length - 1] === DIR_SEPARATOR) { + pathWithoutSlash = pathWithoutSlash.substr(0, pathWithoutSlash.length - 1); + } + + var valPartsLen = pathWithoutSlash.split(DIR_SEPARATOR).length; + var fullPathPartsLen = fullPath.split(DIR_SEPARATOR).length; + + /* Input fullPath parameter equals '//' for root folder */ + /* Entries in root folder has valPartsLen equals 2 (see below) */ + if (fullPath[fullPath.length -1] === DIR_SEPARATOR && fullPath.trim().length === 2) { + fullPathPartsLen = 1; + } else if (fullPath[fullPath.length -1] === DIR_SEPARATOR) { + fullPathPartsLen = fullPath.substr(0, fullPath.length - 1).split(DIR_SEPARATOR).length; + } else { + fullPathPartsLen = fullPath.split(DIR_SEPARATOR).length; + } + + if (valPartsLen === fullPathPartsLen + 1) { + // If this a subfolder and entry is a direct child, include it in + // the results. Otherwise, it's not an entry of this folder. + return val; + } else return false; + }); + + successCallback(results); + }; + + var request = tx.objectStore(FILE_STORE_).openCursor(range); + + request.onsuccess = function(e) { + var cursor = e.target.result; + if (cursor) { + var val = cursor.value; + + results.push(val.isFile ? fileEntryFromIdbEntry(val) : new DirectoryEntry(val.name, val.fullPath, val.filesystem)); + cursor['continue'](); + } + }; + }; + + idb_['delete'] = function(fullPath, successCallback, errorCallback, isDirectory) { + if (!idb_.db) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var tx = this.db.transaction([FILE_STORE_], 'readwrite'); + tx.oncomplete = successCallback; + tx.onabort = errorCallback || onError; + tx.oncomplete = function() { + if (isDirectory) { + //We delete nested files and folders after deleting parent folder + //We use ranges: https://developer.mozilla.org/en-US/docs/Web/API/IDBKeyRange + fullPath = fullPath + DIR_SEPARATOR; + + //Range contains all entries in the form fullPath where + //symbol in the range from ' ' to symbol which has code `unicodeLastChar` + var range = IDBKeyRange.bound(fullPath + ' ', fullPath + String.fromCharCode(unicodeLastChar)); + + var newTx = this.db.transaction([FILE_STORE_], 'readwrite'); + newTx.oncomplete = successCallback; + newTx.onabort = errorCallback || onError; + newTx.objectStore(FILE_STORE_)['delete'](range); + } else { + successCallback(); + } + }; + tx.objectStore(FILE_STORE_)['delete'](fullPath); + }; + + idb_.put = function(entry, storagePath, successCallback, errorCallback) { + if (!this.db) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var tx = this.db.transaction([FILE_STORE_], 'readwrite'); + tx.onabort = errorCallback || onError; + tx.oncomplete = function() { + // TODO: Error is thrown if we pass the request event back instead. + successCallback(entry); + }; + + tx.objectStore(FILE_STORE_).put(entry, storagePath); + }; + + // Global error handler. Errors bubble from request, to transaction, to db. + function onError(e) { + switch (e.target.errorCode) { + case 12: + console.log('Error - Attempt to open db with a lower version than the ' + + 'current one.'); + break; + default: + console.log('errorCode: ' + e.target.errorCode); + } + + console.log(e, e.code, e.message); + } + + })(module.exports, window); + + require("cordova/exec/proxy").add("File", module.exports); +})(); diff --git a/mobile/plugins/cordova-plugin-file/src/firefoxos/FileProxy.js b/mobile/plugins/cordova-plugin-file/src/firefoxos/FileProxy.js new file mode 100644 index 0000000..946304b --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/firefoxos/FileProxy.js @@ -0,0 +1,805 @@ +/* + * + * 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. + * + */ + +/* global IDBKeyRange */ + +var LocalFileSystem = require('./LocalFileSystem'), + FileSystem = require('./FileSystem'), + FileEntry = require('./FileEntry'), + FileError = require('./FileError'), + DirectoryEntry = require('./DirectoryEntry'), + File = require('./File'); + +/* +QUIRKS: + Does not fail when removing non-empty directories + Does not support metadata for directories + Does not support requestAllFileSystems + Does not support resolveLocalFileSystemURI + Methods copyTo and moveTo do not support directories + + Heavily based on https://github.com/ebidel/idb.filesystem.js + */ + + +(function(exports, global) { + var indexedDB = global.indexedDB || global.mozIndexedDB; + if (!indexedDB) { + throw "Firefox OS File plugin: indexedDB not supported"; + } + + var fs_ = null; + + var idb_ = {}; + idb_.db = null; + var FILE_STORE_ = 'entries'; + + var DIR_SEPARATOR = '/'; + var DIR_OPEN_BOUND = String.fromCharCode(DIR_SEPARATOR.charCodeAt(0) + 1); + + var pathsPrefix = { + // Read-only directory where the application is installed. + applicationDirectory: location.origin + "/", + // Where to put app-specific data files. + dataDirectory: 'file:///persistent/', + // Cached files that should survive app restarts. + // Apps should not rely on the OS to delete files in here. + cacheDirectory: 'file:///temporary/', + }; + +/*** Exported functionality ***/ + + exports.requestFileSystem = function(successCallback, errorCallback, args) { + var type = args[0]; + //var size = args[1]; + + if (type !== LocalFileSystem.TEMPORARY && type !== LocalFileSystem.PERSISTENT) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var name = type === LocalFileSystem.TEMPORARY ? 'temporary' : 'persistent'; + var storageName = (location.protocol + location.host).replace(/:/g, '_'); + + var root = new DirectoryEntry('', DIR_SEPARATOR); + fs_ = new FileSystem(name, root); + + idb_.open(storageName, function() { + successCallback(fs_); + }, errorCallback); + }; + + require('./fileSystems').getFs = function(name, callback) { + callback(new FileSystem(name, fs_.root)); + }; + + // list a directory's contents (files and folders). + exports.readEntries = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + + if (!successCallback) { + throw Error('Expected successCallback argument.'); + } + + var path = resolveToFullPath_(fullPath); + + idb_.getAllEntries(path.fullPath, path.storagePath, function(entries) { + successCallback(entries); + }, errorCallback); + }; + + exports.getFile = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + var path = args[1]; + var options = args[2] || {}; + + // Create an absolute path if we were handed a relative one. + path = resolveToFullPath_(fullPath, path); + + idb_.get(path.storagePath, function(fileEntry) { + if (options.create === true && options.exclusive === true && fileEntry) { + // If create and exclusive are both true, and the path already exists, + // getFile must fail. + + if (errorCallback) { + errorCallback(FileError.PATH_EXISTS_ERR); + } + } else if (options.create === true && !fileEntry) { + // If create is true, the path doesn't exist, and no other error occurs, + // getFile must create it as a zero-length file and return a corresponding + // FileEntry. + var newFileEntry = new FileEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root)); + + newFileEntry.file_ = new MyFile({ + size: 0, + name: newFileEntry.name, + lastModifiedDate: new Date(), + storagePath: path.storagePath + }); + + idb_.put(newFileEntry, path.storagePath, successCallback, errorCallback); + } else if (options.create === true && fileEntry) { + if (fileEntry.isFile) { + // Overwrite file, delete then create new. + idb_['delete'](path.storagePath, function() { + var newFileEntry = new FileEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root)); + + newFileEntry.file_ = new MyFile({ + size: 0, + name: newFileEntry.name, + lastModifiedDate: new Date(), + storagePath: path.storagePath + }); + + idb_.put(newFileEntry, path.storagePath, successCallback, errorCallback); + }, errorCallback); + } else { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + } + } else if ((!options.create || options.create === false) && !fileEntry) { + // If create is not true and the path doesn't exist, getFile must fail. + if (errorCallback) { + errorCallback(FileError.NOT_FOUND_ERR); + } + } else if ((!options.create || options.create === false) && fileEntry && + fileEntry.isDirectory) { + // If create is not true and the path exists, but is a directory, getFile + // must fail. + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + } else { + // Otherwise, if no other error occurs, getFile must return a FileEntry + // corresponding to path. + + successCallback(fileEntryFromIdbEntry(fileEntry)); + } + }, errorCallback); + }; + + exports.getFileMetadata = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + + exports.getFile(function(fileEntry) { + successCallback(new File(fileEntry.file_.name, fileEntry.fullPath, '', fileEntry.file_.lastModifiedDate, + fileEntry.file_.size)); + }, errorCallback, [fullPath, null]); + }; + + exports.getMetadata = function(successCallback, errorCallback, args) { + exports.getFile(function (fileEntry) { + successCallback( + { + modificationTime: fileEntry.file_.lastModifiedDate, + size: fileEntry.file_.lastModifiedDate + }); + }, errorCallback, args); + }; + + exports.setMetadata = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + var metadataObject = args[1]; + + exports.getFile(function (fileEntry) { + fileEntry.file_.lastModifiedDate = metadataObject.modificationTime; + }, errorCallback, [fullPath, null]); + }; + + exports.write = function(successCallback, errorCallback, args) { + var fileName = args[0], + data = args[1], + position = args[2]; + //isBinary = args[3]; + + if (!data) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + exports.getFile(function(fileEntry) { + var blob_ = fileEntry.file_.blob_; + + if (!blob_) { + blob_ = new Blob([data], {type: data.type}); + } else { + // Calc the head and tail fragments + var head = blob_.slice(0, position); + var tail = blob_.slice(position + data.byteLength); + + // Calc the padding + var padding = position - head.size; + if (padding < 0) { + padding = 0; + } + + // Do the "write". In fact, a full overwrite of the Blob. + blob_ = new Blob([head, new Uint8Array(padding), data, tail], + {type: data.type}); + } + + // Set the blob we're writing on this file entry so we can recall it later. + fileEntry.file_.blob_ = blob_; + fileEntry.file_.lastModifiedDate = data.lastModifiedDate || null; + fileEntry.file_.size = blob_.size; + fileEntry.file_.name = blob_.name; + fileEntry.file_.type = blob_.type; + + idb_.put(fileEntry, fileEntry.file_.storagePath, function() { + successCallback(data.byteLength); + }, errorCallback); + }, errorCallback, [fileName, null]); + }; + + exports.readAsText = function(successCallback, errorCallback, args) { + var fileName = args[0], + enc = args[1], + startPos = args[2], + endPos = args[3]; + + readAs('text', fileName, enc, startPos, endPos, successCallback, errorCallback); + }; + + exports.readAsDataURL = function(successCallback, errorCallback, args) { + var fileName = args[0], + startPos = args[1], + endPos = args[2]; + + readAs('dataURL', fileName, null, startPos, endPos, successCallback, errorCallback); + }; + + exports.readAsBinaryString = function(successCallback, errorCallback, args) { + var fileName = args[0], + startPos = args[1], + endPos = args[2]; + + readAs('binaryString', fileName, null, startPos, endPos, successCallback, errorCallback); + }; + + exports.readAsArrayBuffer = function(successCallback, errorCallback, args) { + var fileName = args[0], + startPos = args[1], + endPos = args[2]; + + readAs('arrayBuffer', fileName, null, startPos, endPos, successCallback, errorCallback); + }; + + exports.removeRecursively = exports.remove = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + + // TODO: This doesn't protect against directories that have content in it. + // Should throw an error instead if the dirEntry is not empty. + idb_['delete'](fullPath, function() { + successCallback(); + }, errorCallback); + }; + + exports.getDirectory = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + var path = args[1]; + var options = args[2]; + + // Create an absolute path if we were handed a relative one. + path = resolveToFullPath_(fullPath, path); + + idb_.get(path.storagePath, function(folderEntry) { + if (!options) { + options = {}; + } + + if (options.create === true && options.exclusive === true && folderEntry) { + // If create and exclusive are both true, and the path already exists, + // getDirectory must fail. + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + } else if (options.create === true && !folderEntry) { + // If create is true, the path doesn't exist, and no other error occurs, + // getDirectory must create it as a zero-length file and return a corresponding + // MyDirectoryEntry. + var dirEntry = new DirectoryEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root)); + + idb_.put(dirEntry, path.storagePath, successCallback, errorCallback); + } else if (options.create === true && folderEntry) { + + if (folderEntry.isDirectory) { + // IDB won't save methods, so we need re-create the MyDirectoryEntry. + successCallback(new DirectoryEntry(folderEntry.name, folderEntry.fullPath, folderEntry.fileSystem)); + } else { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + } + } else if ((!options.create || options.create === false) && !folderEntry) { + // Handle root special. It should always exist. + if (path.fullPath === DIR_SEPARATOR) { + successCallback(fs_.root); + return; + } + + // If create is not true and the path doesn't exist, getDirectory must fail. + if (errorCallback) { + errorCallback(FileError.NOT_FOUND_ERR); + } + } else if ((!options.create || options.create === false) && folderEntry && + folderEntry.isFile) { + // If create is not true and the path exists, but is a file, getDirectory + // must fail. + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + } else { + // Otherwise, if no other error occurs, getDirectory must return a + // MyDirectoryEntry corresponding to path. + + // IDB won't' save methods, so we need re-create MyDirectoryEntry. + successCallback(new DirectoryEntry(folderEntry.name, folderEntry.fullPath, folderEntry.fileSystem)); + } + }, errorCallback); + }; + + exports.getParent = function(successCallback, errorCallback, args) { + var fullPath = args[0]; + + if (fullPath === DIR_SEPARATOR) { + successCallback(fs_.root); + return; + } + + var pathArr = fullPath.split(DIR_SEPARATOR); + pathArr.pop(); + var namesa = pathArr.pop(); + var path = pathArr.join(DIR_SEPARATOR); + + exports.getDirectory(successCallback, errorCallback, [path, namesa, {create: false}]); + }; + + exports.copyTo = function(successCallback, errorCallback, args) { + var srcPath = args[0]; + var parentFullPath = args[1]; + var name = args[2]; + + // Read src file + exports.getFile(function(srcFileEntry) { + + // Create dest file + exports.getFile(function(dstFileEntry) { + + exports.write(function() { + successCallback(dstFileEntry); + }, errorCallback, [dstFileEntry.file_.storagePath, srcFileEntry.file_.blob_, 0]); + + }, errorCallback, [parentFullPath, name, {create: true}]); + + }, errorCallback, [srcPath, null]); + }; + + exports.moveTo = function(successCallback, errorCallback, args) { + var srcPath = args[0]; + //var parentFullPath = args[1]; + //var name = args[2]; + + exports.copyTo(function (fileEntry) { + + exports.remove(function () { + successCallback(fileEntry); + }, errorCallback, [srcPath]); + + }, errorCallback, args); + }; + + exports.resolveLocalFileSystemURI = function(successCallback, errorCallback, args) { + var path = args[0]; + + // Ignore parameters + if (path.indexOf('?') !== -1) { + path = String(path).split("?")[0]; + } + + // support for encodeURI + if (/\%5/g.test(path)) { + path = decodeURI(path); + } + + if (path.indexOf(pathsPrefix.dataDirectory) === 0) { + path = path.substring(pathsPrefix.dataDirectory.length - 1); + + exports.requestFileSystem(function(fs) { + fs.root.getFile(path, {create: false}, successCallback, function() { + fs.root.getDirectory(path, {create: false}, successCallback, errorCallback); + }); + }, errorCallback, [LocalFileSystem.PERSISTENT]); + } else if (path.indexOf(pathsPrefix.cacheDirectory) === 0) { + path = path.substring(pathsPrefix.cacheDirectory.length - 1); + + exports.requestFileSystem(function(fs) { + fs.root.getFile(path, {create: false}, successCallback, function() { + fs.root.getDirectory(path, {create: false}, successCallback, errorCallback); + }); + }, errorCallback, [LocalFileSystem.TEMPORARY]); + } else if (path.indexOf(pathsPrefix.applicationDirectory) === 0) { + path = path.substring(pathsPrefix.applicationDirectory.length); + + var xhr = new XMLHttpRequest(); + xhr.open("GET", path, true); + xhr.onreadystatechange = function () { + if (xhr.status === 200 && xhr.readyState === 4) { + exports.requestFileSystem(function(fs) { + fs.name = location.hostname; + fs.root.getFile(path, {create: true}, writeFile, errorCallback); + }, errorCallback, [LocalFileSystem.PERSISTENT]); + } + }; + + xhr.onerror = function () { + if (errorCallback) { + errorCallback(FileError.NOT_READABLE_ERR); + } + }; + + xhr.send(); + } else { + if (errorCallback) { + errorCallback(FileError.NOT_FOUND_ERR); + } + } + + function writeFile(entry) { + entry.createWriter(function (fileWriter) { + fileWriter.onwriteend = function (evt) { + if (!evt.target.error) { + entry.filesystemName = location.hostname; + successCallback(entry); + } + }; + fileWriter.onerror = function () { + if (errorCallback) { + errorCallback(FileError.NOT_READABLE_ERR); + } + }; + fileWriter.write(new Blob([xhr.response])); + }, errorCallback); + } + }; + + exports.requestAllPaths = function(successCallback) { + successCallback(pathsPrefix); + }; + +/*** Helpers ***/ + + /** + * Interface to wrap the native File interface. + * + * This interface is necessary for creating zero-length (empty) files, + * something the Filesystem API allows you to do. Unfortunately, File's + * constructor cannot be called directly, making it impossible to instantiate + * an empty File in JS. + * + * @param {Object} opts Initial values. + * @constructor + */ + function MyFile(opts) { + var blob_ = new Blob(); + + this.size = opts.size || 0; + this.name = opts.name || ''; + this.type = opts.type || ''; + this.lastModifiedDate = opts.lastModifiedDate || null; + this.storagePath = opts.storagePath || ''; + + // Need some black magic to correct the object's size/name/type based on the + // blob that is saved. + Object.defineProperty(this, 'blob_', { + enumerable: true, + get: function() { + return blob_; + }, + set: function(val) { + blob_ = val; + this.size = blob_.size; + this.name = blob_.name; + this.type = blob_.type; + this.lastModifiedDate = blob_.lastModifiedDate; + }.bind(this) + }); + } + + MyFile.prototype.constructor = MyFile; + + // When saving an entry, the fullPath should always lead with a slash and never + // end with one (e.g. a directory). Also, resolve '.' and '..' to an absolute + // one. This method ensures path is legit! + function resolveToFullPath_(cwdFullPath, path) { + path = path || ''; + var fullPath = path; + var prefix = ''; + + cwdFullPath = cwdFullPath || DIR_SEPARATOR; + if (cwdFullPath.indexOf(FILESYSTEM_PREFIX) === 0) { + prefix = cwdFullPath.substring(0, cwdFullPath.indexOf(DIR_SEPARATOR, FILESYSTEM_PREFIX.length)); + cwdFullPath = cwdFullPath.substring(cwdFullPath.indexOf(DIR_SEPARATOR, FILESYSTEM_PREFIX.length)); + } + + var relativePath = path[0] !== DIR_SEPARATOR; + if (relativePath) { + fullPath = cwdFullPath; + if (cwdFullPath != DIR_SEPARATOR) { + fullPath += DIR_SEPARATOR + path; + } else { + fullPath += path; + } + } + + // Adjust '..'s by removing parent directories when '..' flows in path. + var parts = fullPath.split(DIR_SEPARATOR); + for (var i = 0; i < parts.length; ++i) { + var part = parts[i]; + if (part == '..') { + parts[i - 1] = ''; + parts[i] = ''; + } + } + fullPath = parts.filter(function(el) { + return el; + }).join(DIR_SEPARATOR); + + // Add back in leading slash. + if (fullPath[0] !== DIR_SEPARATOR) { + fullPath = DIR_SEPARATOR + fullPath; + } + + // Replace './' by current dir. ('./one/./two' -> one/two) + fullPath = fullPath.replace(/\.\//g, DIR_SEPARATOR); + + // Replace '//' with '/'. + fullPath = fullPath.replace(/\/\//g, DIR_SEPARATOR); + + // Replace '/.' with '/'. + fullPath = fullPath.replace(/\/\./g, DIR_SEPARATOR); + + // Remove '/' if it appears on the end. + if (fullPath[fullPath.length - 1] == DIR_SEPARATOR && + fullPath != DIR_SEPARATOR) { + fullPath = fullPath.substring(0, fullPath.length - 1); + } + + return { + storagePath: prefix + fullPath, + fullPath: fullPath, + fileName: fullPath.split(DIR_SEPARATOR).pop(), + fsName: prefix.split(DIR_SEPARATOR).pop() + }; + } + + function fileEntryFromIdbEntry(fileEntry) { + // IDB won't save methods, so we need re-create the FileEntry. + var clonedFileEntry = new FileEntry(fileEntry.name, fileEntry.fullPath, fileEntry.fileSystem); + clonedFileEntry.file_ = fileEntry.file_; + + return clonedFileEntry; + } + + function readAs(what, fullPath, encoding, startPos, endPos, successCallback, errorCallback) { + exports.getFile(function(fileEntry) { + var fileReader = new FileReader(), + blob = fileEntry.file_.blob_.slice(startPos, endPos); + + fileReader.onload = function(e) { + successCallback(e.target.result); + }; + + fileReader.onerror = errorCallback; + + switch (what) { + case 'text': + fileReader.readAsText(blob, encoding); + break; + case 'dataURL': + fileReader.readAsDataURL(blob); + break; + case 'arrayBuffer': + fileReader.readAsArrayBuffer(blob); + break; + case 'binaryString': + fileReader.readAsBinaryString(blob); + break; + } + + }, errorCallback, [fullPath, null]); + } + +/*** Core logic to handle IDB operations ***/ + + idb_.open = function(dbName, successCallback, errorCallback) { + var self = this; + + // TODO: FF 12.0a1 isn't liking a db name with : in it. + var request = indexedDB.open(dbName.replace(':', '_')/*, 1 /*version*/); + + request.onerror = errorCallback || onError; + + request.onupgradeneeded = function(e) { + // First open was called or higher db version was used. + + // console.log('onupgradeneeded: oldVersion:' + e.oldVersion, + // 'newVersion:' + e.newVersion); + + self.db = e.target.result; + self.db.onerror = onError; + + if (!self.db.objectStoreNames.contains(FILE_STORE_)) { + self.db.createObjectStore(FILE_STORE_/*,{keyPath: 'id', autoIncrement: true}*/); + } + }; + + request.onsuccess = function(e) { + self.db = e.target.result; + self.db.onerror = onError; + successCallback(e); + }; + + request.onblocked = errorCallback || onError; + }; + + idb_.close = function() { + this.db.close(); + this.db = null; + }; + + idb_.get = function(fullPath, successCallback, errorCallback) { + if (!this.db) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var tx = this.db.transaction([FILE_STORE_], 'readonly'); + + //var request = tx.objectStore(FILE_STORE_).get(fullPath); + var range = IDBKeyRange.bound(fullPath, fullPath + DIR_OPEN_BOUND, + false, true); + var request = tx.objectStore(FILE_STORE_).get(range); + + tx.onabort = errorCallback || onError; + tx.oncomplete = function(e) { + successCallback(request.result); + }; + }; + + idb_.getAllEntries = function(fullPath, storagePath, successCallback, errorCallback) { + if (!this.db) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var results = []; + + if (storagePath[storagePath.length - 1] === DIR_SEPARATOR) { + storagePath = storagePath.substring(0, storagePath.length - 1); + } + + var range = IDBKeyRange.bound( + storagePath + DIR_SEPARATOR, storagePath + DIR_OPEN_BOUND, false, true); + + var tx = this.db.transaction([FILE_STORE_], 'readonly'); + tx.onabort = errorCallback || onError; + tx.oncomplete = function(e) { + results = results.filter(function(val) { + var valPartsLen = val.fullPath.split(DIR_SEPARATOR).length; + var fullPathPartsLen = fullPath.split(DIR_SEPARATOR).length; + + if (fullPath === DIR_SEPARATOR && valPartsLen < fullPathPartsLen + 1) { + // Hack to filter out entries in the root folder. This is inefficient + // because reading the entires of fs.root (e.g. '/') returns ALL + // results in the database, then filters out the entries not in '/'. + return val; + } else if (fullPath !== DIR_SEPARATOR && + valPartsLen === fullPathPartsLen + 1) { + // If this a subfolder and entry is a direct child, include it in + // the results. Otherwise, it's not an entry of this folder. + return val; + } + }); + + successCallback(results); + }; + + var request = tx.objectStore(FILE_STORE_).openCursor(range); + + request.onsuccess = function(e) { + var cursor = e.target.result; + if (cursor) { + var val = cursor.value; + + results.push(val.isFile ? fileEntryFromIdbEntry(val) : new DirectoryEntry(val.name, val.fullPath, val.fileSystem)); + cursor['continue'](); + } + }; + }; + + idb_['delete'] = function(fullPath, successCallback, errorCallback) { + if (!this.db) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var tx = this.db.transaction([FILE_STORE_], 'readwrite'); + tx.oncomplete = successCallback; + tx.onabort = errorCallback || onError; + + //var request = tx.objectStore(FILE_STORE_).delete(fullPath); + var range = IDBKeyRange.bound( + fullPath, fullPath + DIR_OPEN_BOUND, false, true); + tx.objectStore(FILE_STORE_)['delete'](range); + }; + + idb_.put = function(entry, storagePath, successCallback, errorCallback) { + if (!this.db) { + if (errorCallback) { + errorCallback(FileError.INVALID_MODIFICATION_ERR); + } + return; + } + + var tx = this.db.transaction([FILE_STORE_], 'readwrite'); + tx.onabort = errorCallback || onError; + tx.oncomplete = function(e) { + // TODO: Error is thrown if we pass the request event back instead. + successCallback(entry); + }; + + tx.objectStore(FILE_STORE_).put(entry, storagePath); + }; + + // Global error handler. Errors bubble from request, to transaction, to db. + function onError(e) { + switch (e.target.errorCode) { + case 12: + console.log('Error - Attempt to open db with a lower version than the ' + + 'current one.'); + break; + default: + console.log('errorCode: ' + e.target.errorCode); + } + + console.log(e, e.code, e.message); + } + +// Clean up. +// TODO: Is there a place for this? +// global.addEventListener('beforeunload', function(e) { +// idb_.db && idb_.db.close(); +// }, false); + +})(module.exports, window); + +require("cordova/exec/proxy").add("File", module.exports); diff --git a/mobile/plugins/cordova-plugin-file/src/ios/CDVAssetLibraryFilesystem.h b/mobile/plugins/cordova-plugin-file/src/ios/CDVAssetLibraryFilesystem.h new file mode 100644 index 0000000..e09e225 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/ios/CDVAssetLibraryFilesystem.h @@ -0,0 +1,30 @@ +/* + 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. + */ + +#import "CDVFile.h" + +extern NSString* const kCDVAssetsLibraryPrefix; +extern NSString* const kCDVAssetsLibraryScheme; + +@interface CDVAssetLibraryFilesystem : NSObject { +} + +- (id) initWithName:(NSString *)name; + +@end diff --git a/mobile/plugins/cordova-plugin-file/src/ios/CDVAssetLibraryFilesystem.m b/mobile/plugins/cordova-plugin-file/src/ios/CDVAssetLibraryFilesystem.m new file mode 100644 index 0000000..8486b7b --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/ios/CDVAssetLibraryFilesystem.m @@ -0,0 +1,253 @@ +/* + 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. + */ + +#import "CDVFile.h" +#import "CDVAssetLibraryFilesystem.h" +#import +#import +#import +#import +#import + +NSString* const kCDVAssetsLibraryPrefix = @"assets-library://"; +NSString* const kCDVAssetsLibraryScheme = @"assets-library"; + +@implementation CDVAssetLibraryFilesystem +@synthesize name=_name, urlTransformer; + + +/* + The CDVAssetLibraryFilesystem works with resources which are identified + by iOS as + asset-library:// + and represents them internally as URLs of the form + cdvfile://localhost/assets-library/ + */ + +- (NSURL *)assetLibraryURLForLocalURL:(CDVFilesystemURL *)url +{ + if ([url.url.scheme isEqualToString:kCDVFilesystemURLPrefix]) { + NSString *path = [[url.url absoluteString] substringFromIndex:[@"cdvfile://localhost/assets-library" length]]; + return [NSURL URLWithString:[NSString stringWithFormat:@"assets-library:/%@", path]]; + } + return url.url; +} + +- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url +{ + NSDictionary* entry = [self makeEntryForLocalURL:url]; + return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:entry]; +} + +- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url { + return [self makeEntryForPath:url.fullPath isDirectory:NO]; +} + +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir +{ + NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5]; + NSString* lastPart = [fullPath lastPathComponent]; + if (isDir && ![fullPath hasSuffix:@"/"]) { + fullPath = [fullPath stringByAppendingString:@"/"]; + } + [dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"]; + [dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"]; + [dirEntry setObject:fullPath forKey:@"fullPath"]; + [dirEntry setObject:lastPart forKey:@"name"]; + [dirEntry setObject:self.name forKey: @"filesystemName"]; + + NSURL* nativeURL = [NSURL URLWithString:[NSString stringWithFormat:@"assets-library:/%@",fullPath]]; + if (self.urlTransformer) { + nativeURL = self.urlTransformer(nativeURL); + } + dirEntry[@"nativeURL"] = [nativeURL absoluteString]; + + return dirEntry; +} + +/* helper function to get the mimeType from the file extension + * IN: + * NSString* fullPath - filename (may include path) + * OUT: + * NSString* the mime type as type/subtype. nil if not able to determine + */ ++ (NSString*)getMimeTypeFromPath:(NSString*)fullPath +{ + NSString* mimeType = nil; + + if (fullPath) { + CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL); + if (typeId) { + mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType); + if (!mimeType) { + // special case for m4a + if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) { + mimeType = @"audio/mp4"; + } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) { + mimeType = @"audio/wav"; + } else if ([[fullPath pathExtension] rangeOfString:@"css"].location != NSNotFound) { + mimeType = @"text/css"; + } + } + CFRelease(typeId); + } + } + return mimeType; +} + +- (id)initWithName:(NSString *)name +{ + if (self) { + self.name = name; + } + return self; +} + +- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options +{ + // return unsupported result for assets-library URLs + return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."]; +} + +- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI +{ + // we don't (yet?) support getting the parent of an asset + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR]; +} + +- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options +{ + // setMetadata doesn't make sense for asset library files + return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; +} + +- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI +{ + // return error for assets-library URLs + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR]; +} + +- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI +{ + // return error for assets-library URLs + return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."]; +} + +- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI +{ + // return unsupported result for assets-library URLs + return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."]; +} + +- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos +{ + // assets-library files can't be truncated + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; +} + +- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend +{ + // text can't be written into assets-library files + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; +} + +- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback +{ + // Copying to an assets library file is not doable, since we can't write it. + CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR]; + callback(result); +} + +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)url +{ + NSString *path = nil; + if ([[url.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) { + path = [url.url path]; + } else { + path = url.fullPath; + } + if ([path hasSuffix:@"/"]) { + path = [path substringToIndex:([path length]-1)]; + } + return path; +} + +- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback +{ + ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { + if (asset) { + // We have the asset! Get the data and send it off. + ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; + NSUInteger size = (end > start) ? (end - start) : [assetRepresentation size]; + Byte* buffer = (Byte*)malloc(size); + NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:start length:size error:nil]; + NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; + NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType); + + callback(data, MIMEType, NO_ERROR); + } else { + callback(nil, nil, NOT_FOUND_ERR); + } + }; + + ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { + // Retrieving the asset failed for some reason. Send the appropriate error. + NSLog(@"Error: %@", error); + callback(nil, nil, SECURITY_ERR); + }; + + ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; + [assetsLibrary assetForURL:[self assetLibraryURLForLocalURL:localURL] resultBlock:resultBlock failureBlock:failureBlock]; +} + +- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback +{ + // In this case, we need to use an asynchronous method to retrieve the file. + // Because of this, we can't just assign to `result` and send it at the end of the method. + // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. + ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { + if (asset) { + // We have the asset! Populate the dictionary and send it off. + NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5]; + ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; + [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"]; + [fileInfo setObject:localURL.fullPath forKey:@"fullPath"]; + NSString* filename = [assetRepresentation filename]; + [fileInfo setObject:filename forKey:@"name"]; + [fileInfo setObject:[CDVAssetLibraryFilesystem getMimeTypeFromPath:filename] forKey:@"type"]; + NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate]; + NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000]; + [fileInfo setObject:msDate forKey:@"lastModifiedDate"]; + + callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]); + } else { + // We couldn't find the asset. Send the appropriate error. + callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]); + } + }; + ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { + // Retrieving the asset failed for some reason. Send the appropriate error. + callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]); + }; + + ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; + [assetsLibrary assetForURL:[self assetLibraryURLForLocalURL:localURL] resultBlock:resultBlock failureBlock:failureBlock]; + return; +} +@end diff --git a/mobile/plugins/cordova-plugin-file/src/ios/CDVFile.h b/mobile/plugins/cordova-plugin-file/src/ios/CDVFile.h new file mode 100644 index 0000000..987c66b --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/ios/CDVFile.h @@ -0,0 +1,157 @@ +/* + 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. + */ + +#import +#import + +extern NSString* const kCDVAssetsLibraryPrefix; +extern NSString* const kCDVFilesystemURLPrefix; + +enum CDVFileError { + NO_ERROR = 0, + NOT_FOUND_ERR = 1, + SECURITY_ERR = 2, + ABORT_ERR = 3, + NOT_READABLE_ERR = 4, + ENCODING_ERR = 5, + NO_MODIFICATION_ALLOWED_ERR = 6, + INVALID_STATE_ERR = 7, + SYNTAX_ERR = 8, + INVALID_MODIFICATION_ERR = 9, + QUOTA_EXCEEDED_ERR = 10, + TYPE_MISMATCH_ERR = 11, + PATH_EXISTS_ERR = 12 +}; +typedef int CDVFileError; + +@interface CDVFilesystemURL : NSObject { + NSURL *_url; + NSString *_fileSystemName; + NSString *_fullPath; +} + +- (id) initWithString:(NSString*)strURL; +- (id) initWithURL:(NSURL*)URL; ++ (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL; ++ (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL; + +- (NSString *)absoluteURL; + +@property (atomic) NSURL *url; +@property (atomic) NSString *fileSystemName; +@property (atomic) NSString *fullPath; + +@end + +@interface CDVFilesystemURLProtocol : NSURLProtocol +@end + +@protocol CDVFileSystem +- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url; +- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options; +- (CDVPluginResult *)getParentForURL:(CDVFilesystemURL *)localURI; +- (CDVPluginResult *)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options; +- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI; +- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI; +- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI; +- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos; +- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend; +- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback; +- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback; +- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback; + +- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url; +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir; + +@property (nonatomic,strong) NSString *name; +@property (nonatomic, copy) NSURL*(^urlTransformer)(NSURL*); + +@optional +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)localURI; +- (CDVFilesystemURL *)URLforFilesystemPath:(NSString *)path; + +@end + +@interface CDVFile : CDVPlugin { + NSString* rootDocsPath; + NSString* appDocsPath; + NSString* appLibraryPath; + NSString* appTempPath; + + NSMutableArray* fileSystems_; + BOOL userHasAllowed; +} + +- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath; +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystemName:(NSString *)fsName isDirectory:(BOOL)isDir; +- (NSDictionary *)makeEntryForURL:(NSURL *)URL; +- (CDVFilesystemURL *)fileSystemURLforLocalPath:(NSString *)localPath; + +- (NSObject *)filesystemForURL:(CDVFilesystemURL *)localURL; + +/* Native Registration API */ +- (void)registerFilesystem:(NSObject *)fs; +- (NSObject *)fileSystemByName:(NSString *)fsName; + +/* Exec API */ +- (void)requestFileSystem:(CDVInvokedUrlCommand*)command; +- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command; +- (void)getDirectory:(CDVInvokedUrlCommand*)command; +- (void)getFile:(CDVInvokedUrlCommand*)command; +- (void)getParent:(CDVInvokedUrlCommand*)command; +- (void)removeRecursively:(CDVInvokedUrlCommand*)command; +- (void)remove:(CDVInvokedUrlCommand*)command; +- (void)copyTo:(CDVInvokedUrlCommand*)command; +- (void)moveTo:(CDVInvokedUrlCommand*)command; +- (void)getFileMetadata:(CDVInvokedUrlCommand*)command; +- (void)readEntries:(CDVInvokedUrlCommand*)command; +- (void)readAsText:(CDVInvokedUrlCommand*)command; +- (void)readAsDataURL:(CDVInvokedUrlCommand*)command; +- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command; +- (void)write:(CDVInvokedUrlCommand*)command; +- (void)testFileExists:(CDVInvokedUrlCommand*)command; +- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command; +- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command; +- (void)truncate:(CDVInvokedUrlCommand*)command; +- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy; + +/* Compatibilty with older File API */ +- (NSString*)getMimeTypeFromPath:(NSString*)fullPath; +- (NSDictionary *)getDirectoryEntry:(NSString *)target isDirectory:(BOOL)bDirRequest; + +/* Conversion between filesystem paths and URLs */ +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)URL; + +/* Internal methods for testing */ +- (void)_getLocalFilesystemPath:(CDVInvokedUrlCommand*)command; + +@property (nonatomic, strong) NSString* rootDocsPath; +@property (nonatomic, strong) NSString* appDocsPath; +@property (nonatomic, strong) NSString* appLibraryPath; +@property (nonatomic, strong) NSString* appTempPath; +@property (nonatomic, strong) NSString* persistentPath; +@property (nonatomic, strong) NSString* temporaryPath; +@property (nonatomic, strong) NSMutableArray* fileSystems; + +@property BOOL userHasAllowed; + +@end + +#define kW3FileTemporary @"temporary" +#define kW3FilePersistent @"persistent" diff --git a/mobile/plugins/cordova-plugin-file/src/ios/CDVFile.m b/mobile/plugins/cordova-plugin-file/src/ios/CDVFile.m new file mode 100644 index 0000000..59e7d64 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/ios/CDVFile.m @@ -0,0 +1,1119 @@ +/* + 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. + */ + +#import +#import "CDVFile.h" +#import "CDVLocalFilesystem.h" +#import "CDVAssetLibraryFilesystem.h" +#import + +static NSString* toBase64(NSData* data) { + SEL s1 = NSSelectorFromString(@"cdv_base64EncodedString"); + SEL s2 = NSSelectorFromString(@"base64EncodedString"); + SEL s3 = NSSelectorFromString(@"base64EncodedStringWithOptions:"); + + if ([data respondsToSelector:s1]) { + NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s1]; + return func(data, s1); + } else if ([data respondsToSelector:s2]) { + NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s2]; + return func(data, s2); + } else if ([data respondsToSelector:s3]) { + NSString* (*func)(id, SEL, NSUInteger) = (void *)[data methodForSelector:s3]; + return func(data, s3, 0); + } else { + return nil; + } +} + +CDVFile *filePlugin = nil; + +extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import)); + +#ifndef __IPHONE_5_1 + NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey"; +#endif + +NSString* const kCDVFilesystemURLPrefix = @"cdvfile"; + +@implementation CDVFilesystemURL +@synthesize url=_url; +@synthesize fileSystemName=_fileSystemName; +@synthesize fullPath=_fullPath; + +- (id) initWithString:(NSString *)strURL +{ + if ( self = [super init] ) { + NSURL *decodedURL = [NSURL URLWithString:strURL]; + return [self initWithURL:decodedURL]; + } + return nil; +} + +-(id) initWithURL:(NSURL *)URL +{ + if ( self = [super init] ) { + self.url = URL; + self.fileSystemName = [self filesystemNameForLocalURI:URL]; + self.fullPath = [self fullPathForLocalURI:URL]; + } + return self; +} + +/* + * IN + * NSString localURI + * OUT + * NSString FileSystem Name for this URI, or nil if it is not recognized. + */ +- (NSString *)filesystemNameForLocalURI:(NSURL *)uri +{ + if ([[uri scheme] isEqualToString:kCDVFilesystemURLPrefix] && [[uri host] isEqualToString:@"localhost"]) { + NSArray *pathComponents = [uri pathComponents]; + if (pathComponents != nil && pathComponents.count > 1) { + return [pathComponents objectAtIndex:1]; + } + } else if ([[uri scheme] isEqualToString:kCDVAssetsLibraryScheme]) { + return @"assets-library"; + } + return nil; +} + +/* + * IN + * NSString localURI + * OUT + * NSString fullPath component suitable for an Entry object. + * The incoming URI should be properly escaped. The returned fullPath is unescaped. + */ +- (NSString *)fullPathForLocalURI:(NSURL *)uri +{ + if ([[uri scheme] isEqualToString:kCDVFilesystemURLPrefix] && [[uri host] isEqualToString:@"localhost"]) { + NSString *path = [uri path]; + if ([uri query]) { + path = [NSString stringWithFormat:@"%@?%@", path, [uri query]]; + } + NSRange slashRange = [path rangeOfString:@"/" options:0 range:NSMakeRange(1, path.length-1)]; + if (slashRange.location == NSNotFound) { + return @""; + } + return [path substringFromIndex:slashRange.location]; + } else if ([[uri scheme] isEqualToString:kCDVAssetsLibraryScheme]) { + return [[uri absoluteString] substringFromIndex:[kCDVAssetsLibraryScheme length]+2]; + } + return nil; +} + ++ (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL +{ + return [[CDVFilesystemURL alloc] initWithString:strURL]; +} + ++ (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL +{ + return [[CDVFilesystemURL alloc] initWithURL:URL]; +} + +- (NSString *)absoluteURL +{ + return [NSString stringWithFormat:@"cdvfile://localhost/%@%@", self.fileSystemName, self.fullPath]; +} + +@end + +@implementation CDVFilesystemURLProtocol + ++ (BOOL)canInitWithRequest:(NSURLRequest*)request +{ + NSURL* url = [request URL]; + return [[url scheme] isEqualToString:kCDVFilesystemURLPrefix]; +} + ++ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request +{ + return request; +} + ++ (BOOL)requestIsCacheEquivalent:(NSURLRequest*)requestA toRequest:(NSURLRequest*)requestB +{ + return [[[requestA URL] resourceSpecifier] isEqualToString:[[requestB URL] resourceSpecifier]]; +} + +- (void)startLoading +{ + CDVFilesystemURL* url = [CDVFilesystemURL fileSystemURLWithURL:[[self request] URL]]; + NSObject *fs = [filePlugin filesystemForURL:url]; + __weak CDVFilesystemURLProtocol* weakSelf = self; + + [fs readFileAtURL:url start:0 end:-1 callback:^void(NSData *data, NSString *mimetype, CDVFileError error) { + NSMutableDictionary* responseHeaders = [[NSMutableDictionary alloc] init]; + responseHeaders[@"Cache-Control"] = @"no-cache"; + + if (!error) { + responseHeaders[@"Content-Type"] = mimetype; + NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url.url statusCode:200 HTTPVersion:@"HTTP/1.1"headerFields:responseHeaders]; + [[weakSelf client] URLProtocol:weakSelf didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + [[weakSelf client] URLProtocol:weakSelf didLoadData:data]; + [[weakSelf client] URLProtocolDidFinishLoading:weakSelf]; + } else { + NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url.url statusCode:404 HTTPVersion:@"HTTP/1.1"headerFields:responseHeaders]; + [[weakSelf client] URLProtocol:weakSelf didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + [[weakSelf client] URLProtocolDidFinishLoading:weakSelf]; + } + }]; +} + +- (void)stopLoading +{} + +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection + willCacheResponse:(NSCachedURLResponse*)cachedResponse { + return nil; +} + +@end + + +@implementation CDVFile + +@synthesize rootDocsPath, appDocsPath, appLibraryPath, appTempPath, userHasAllowed, fileSystems=fileSystems_; + +- (void)registerFilesystem:(NSObject *)fs { + __weak CDVFile* weakSelf = self; + SEL sel = NSSelectorFromString(@"urlTransformer"); + // for backwards compatibility - we check if this property is there + // we create a wrapper block because the urlTransformer property + // on the commandDelegate might be set dynamically at a future time + // (and not dependent on plugin loading order) + if ([self.commandDelegate respondsToSelector:sel]) { + fs.urlTransformer = ^NSURL*(NSURL* urlToTransform) { + // grab the block from the commandDelegate + NSURL* (^urlTransformer)(NSURL*) = ((id(*)(id, SEL))objc_msgSend)(weakSelf.commandDelegate, sel); + // if block is not null, we call it + if (urlTransformer) { + return urlTransformer(urlToTransform); + } else { // else we return the same url + return urlToTransform; + } + }; + } + [fileSystems_ addObject:fs]; +} + +- (NSObject *)fileSystemByName:(NSString *)fsName +{ + if (self.fileSystems != nil) { + for (NSObject *fs in self.fileSystems) { + if ([fs.name isEqualToString:fsName]) { + return fs; + } + } + } + return nil; +} + +- (NSObject *)filesystemForURL:(CDVFilesystemURL *)localURL { + if (localURL.fileSystemName == nil) return nil; + @try { + return [self fileSystemByName:localURL.fileSystemName]; + } + @catch (NSException *e) { + return nil; + } +} + +- (NSArray *)getExtraFileSystemsPreference:(UIViewController *)vc +{ + NSString *filesystemsStr = nil; + if([self.viewController isKindOfClass:[CDVViewController class]]) { + CDVViewController *vc = (CDVViewController *)self.viewController; + NSDictionary *settings = [vc settings]; + filesystemsStr = [settings[@"iosextrafilesystems"] lowercaseString]; + } + if (!filesystemsStr) { + filesystemsStr = @"library,library-nosync,documents,documents-nosync,cache,bundle,root"; + } + return [filesystemsStr componentsSeparatedByString:@","]; +} + +- (void)makeNonSyncable:(NSString*)path { + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSURL* url = [NSURL fileURLWithPath:path]; + [url setResourceValue: [NSNumber numberWithBool: YES] + forKey: NSURLIsExcludedFromBackupKey error:nil]; + +} + +- (void)registerExtraFileSystems:(NSArray *)filesystems fromAvailableSet:(NSDictionary *)availableFileSystems +{ + NSMutableSet *installedFilesystems = [[NSMutableSet alloc] initWithCapacity:7]; + + /* Build non-syncable directories as necessary */ + for (NSString *nonSyncFS in @[@"library-nosync", @"documents-nosync"]) { + if ([filesystems containsObject:nonSyncFS]) { + [self makeNonSyncable:availableFileSystems[nonSyncFS]]; + } + } + + /* Register filesystems in order */ + for (NSString *fsName in filesystems) { + if (![installedFilesystems containsObject:fsName]) { + NSString *fsRoot = availableFileSystems[fsName]; + if (fsRoot) { + [filePlugin registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:fsName root:fsRoot]]; + [installedFilesystems addObject:fsName]; + } else { + NSLog(@"Unrecognized extra filesystem identifier: %@", fsName); + } + } + } +} + +- (NSDictionary *)getAvailableFileSystems +{ + NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + return @{ + @"library": libPath, + @"library-nosync": [libPath stringByAppendingPathComponent:@"NoCloud"], + @"documents": docPath, + @"documents-nosync": [docPath stringByAppendingPathComponent:@"NoCloud"], + @"cache": [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0], + @"bundle": [[NSBundle mainBundle] bundlePath], + @"root": @"/" + }; +} + +- (void)pluginInitialize +{ + filePlugin = self; + [NSURLProtocol registerClass:[CDVFilesystemURLProtocol class]]; + + fileSystems_ = [[NSMutableArray alloc] initWithCapacity:3]; + + // Get the Library directory path + NSArray* paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + self.appLibraryPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"files"]; + + // Get the Temporary directory path + self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath]; // remove trailing slash from NSTemporaryDirectory() + + // Get the Documents directory path + paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + self.rootDocsPath = [paths objectAtIndex:0]; + self.appDocsPath = [self.rootDocsPath stringByAppendingPathComponent:@"files"]; + + + NSString *location = nil; + if([self.viewController isKindOfClass:[CDVViewController class]]) { + CDVViewController *vc = (CDVViewController *)self.viewController; + NSMutableDictionary *settings = vc.settings; + location = [[settings objectForKey:@"iospersistentfilelocation"] lowercaseString]; + } + if (location == nil) { + // Compatibilty by default (if the config preference is not set, or + // if we're not embedded in a CDVViewController somehow.) + location = @"compatibility"; + } + + NSError *error; + if ([[NSFileManager defaultManager] createDirectoryAtPath:self.appTempPath + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + [self registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:@"temporary" root:self.appTempPath]]; + } else { + NSLog(@"Unable to create temporary directory: %@", error); + } + if ([location isEqualToString:@"library"]) { + if ([[NSFileManager defaultManager] createDirectoryAtPath:self.appLibraryPath + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + [self registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:@"persistent" root:self.appLibraryPath]]; + } else { + NSLog(@"Unable to create library directory: %@", error); + } + } else if ([location isEqualToString:@"compatibility"]) { + /* + * Fall-back to compatibility mode -- this is the logic implemented in + * earlier versions of this plugin, and should be maintained here so + * that apps which were originally deployed with older versions of the + * plugin can continue to provide access to files stored under those + * versions. + */ + [self registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:@"persistent" root:self.rootDocsPath]]; + } else { + NSAssert(false, + @"File plugin configuration error: Please set iosPersistentFileLocation in config.xml to one of \"library\" (for new applications) or \"compatibility\" (for compatibility with previous versions)"); + } + [self registerFilesystem:[[CDVAssetLibraryFilesystem alloc] initWithName:@"assets-library"]]; + + [self registerExtraFileSystems:[self getExtraFileSystemsPreference:self.viewController] + fromAvailableSet:[self getAvailableFileSystems]]; + +} + +- (CDVFilesystemURL *)fileSystemURLforArg:(NSString *)urlArg +{ + CDVFilesystemURL* ret = nil; + if ([urlArg hasPrefix:@"file://"]) { + /* This looks like a file url. Get the path, and see if any handlers recognize it. */ + NSURL *fileURL = [NSURL URLWithString:urlArg]; + NSURL *resolvedFileURL = [fileURL URLByResolvingSymlinksInPath]; + NSString *path = [resolvedFileURL path]; + ret = [self fileSystemURLforLocalPath:path]; + } else { + ret = [CDVFilesystemURL fileSystemURLWithString:urlArg]; + } + return ret; +} + +- (CDVFilesystemURL *)fileSystemURLforLocalPath:(NSString *)localPath +{ + CDVFilesystemURL *localURL = nil; + NSUInteger shortestFullPath = 0; + + // Try all installed filesystems, in order. Return the most match url. + for (id object in self.fileSystems) { + if ([object respondsToSelector:@selector(URLforFilesystemPath:)]) { + CDVFilesystemURL *url = [object URLforFilesystemPath:localPath]; + if (url){ + // A shorter fullPath would imply that the filesystem is a better match for the local path + if (!localURL || ([[url fullPath] length] < shortestFullPath)) { + localURL = url; + shortestFullPath = [[url fullPath] length]; + } + } + } + } + return localURL; +} + +- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath +{ + NSFileManager* fMgr = [[NSFileManager alloc] init]; + + NSError* __autoreleasing pError = nil; + + NSDictionary* pDict = [fMgr attributesOfFileSystemForPath:appPath error:&pError]; + NSNumber* pNumAvail = (NSNumber*)[pDict objectForKey:NSFileSystemFreeSize]; + + return pNumAvail; +} + +/* Request the File System info + * + * IN: + * arguments[0] - type (number as string) + * TEMPORARY = 0, PERSISTENT = 1; + * arguments[1] - size + * + * OUT: + * Dictionary representing FileSystem object + * name - the human readable directory name + * root = DirectoryEntry object + * bool isDirectory + * bool isFile + * string name + * string fullPath + * fileSystem = FileSystem object - !! ignored because creates circular reference !! + */ + +- (void)requestFileSystem:(CDVInvokedUrlCommand*)command +{ + // arguments + NSString* strType = [command argumentAtIndex:0]; + unsigned long long size = [[command argumentAtIndex:1] longLongValue]; + + int type = [strType intValue]; + CDVPluginResult* result = nil; + + if (type >= self.fileSystems.count) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR]; + NSLog(@"No filesystem of type requested"); + } else { + NSString* fullPath = @"/"; + // check for avail space for size request + NSNumber* pNumAvail = [self checkFreeDiskSpace:self.rootDocsPath]; + // NSLog(@"Free space: %@", [NSString stringWithFormat:@"%qu", [ pNumAvail unsignedLongLongValue ]]); + if (pNumAvail && ([pNumAvail unsignedLongLongValue] < size)) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:QUOTA_EXCEEDED_ERR]; + } else { + NSObject *rootFs = [self.fileSystems objectAtIndex:type]; + if (rootFs == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR]; + NSLog(@"No filesystem of type requested"); + } else { + NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2]; + [fileSystem setObject:rootFs.name forKey:@"name"]; + NSDictionary* dirEntry = [self makeEntryForPath:fullPath fileSystemName:rootFs.name isDirectory:YES]; + [fileSystem setObject:dirEntry forKey:@"root"]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; + } + } + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + + +- (void)requestAllFileSystems:(CDVInvokedUrlCommand*)command +{ + NSMutableArray* ret = [[NSMutableArray alloc] init]; + for (NSObject* root in fileSystems_) { + [ret addObject:[self makeEntryForPath:@"/" fileSystemName:root.name isDirectory:YES]]; + } + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:ret]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +- (void)requestAllPaths:(CDVInvokedUrlCommand*)command +{ + NSString* libPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0]; + NSString* libPathSync = [libPath stringByAppendingPathComponent:@"Cloud"]; + NSString* libPathNoSync = [libPath stringByAppendingPathComponent:@"NoCloud"]; + NSString* docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + NSString* storagePath = [libPath stringByDeletingLastPathComponent]; + NSString* cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; + + // Create the directories if necessary. + [[NSFileManager defaultManager] createDirectoryAtPath:libPathSync withIntermediateDirectories:YES attributes:nil error:nil]; + [[NSFileManager defaultManager] createDirectoryAtPath:libPathNoSync withIntermediateDirectories:YES attributes:nil error:nil]; + // Mark NoSync as non-iCloud. + [[NSURL fileURLWithPath:libPathNoSync] setResourceValue: [NSNumber numberWithBool: YES] + forKey: NSURLIsExcludedFromBackupKey error:nil]; + + NSDictionary* ret = @{ + @"applicationDirectory": [[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]] absoluteString], + @"applicationStorageDirectory": [[NSURL fileURLWithPath:storagePath] absoluteString], + @"dataDirectory": [[NSURL fileURLWithPath:libPathNoSync] absoluteString], + @"syncedDataDirectory": [[NSURL fileURLWithPath:libPathSync] absoluteString], + @"documentsDirectory": [[NSURL fileURLWithPath:docPath] absoluteString], + @"cacheDirectory": [[NSURL fileURLWithPath:cachePath] absoluteString], + @"tempDirectory": [[NSURL fileURLWithPath:NSTemporaryDirectory()] absoluteString] + }; + + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:ret]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* Creates and returns a dictionary representing an Entry Object + * + * IN: + * NSString* fullPath of the entry + * int fsType - FileSystem type + * BOOL isDirectory - YES if this is a directory, NO if is a file + * OUT: + * NSDictionary* Entry object + * bool as NSNumber isDirectory + * bool as NSNumber isFile + * NSString* name - last part of path + * NSString* fullPath + * NSString* filesystemName - FileSystem name -- actual filesystem will be created on the JS side if necessary, to avoid + * creating circular reference (FileSystem contains DirectoryEntry which contains FileSystem.....!!) + */ +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystemName:(NSString *)fsName isDirectory:(BOOL)isDir +{ + NSObject *fs = [self fileSystemByName:fsName]; + return [fs makeEntryForPath:fullPath isDirectory:isDir]; +} + +- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)localURL +{ + NSObject *fs = [self filesystemForURL:localURL]; + return [fs makeEntryForLocalURL:localURL]; +} + +- (NSDictionary *)makeEntryForURL:(NSURL *)URL +{ + CDVFilesystemURL* fsURL = [self fileSystemURLforArg:[URL absoluteString]]; + return [self makeEntryForLocalURL:fsURL]; +} + +/* + * Given a URI determine the File System information associated with it and return an appropriate W3C entry object + * IN + * NSString* localURI: Should be an escaped local filesystem URI + * OUT + * Entry object + * bool isDirectory + * bool isFile + * string name + * string fullPath + * fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!! + */ +- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command +{ + // arguments + NSString* localURIstr = [command argumentAtIndex:0]; + CDVPluginResult* result; + + localURIstr = [self encodePath:localURIstr]; //encode path before resolving + CDVFilesystemURL* inputURI = [self fileSystemURLforArg:localURIstr]; + + if (inputURI == nil || inputURI.fileSystemName == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; + } else { + NSObject *fs = [self filesystemForURL:inputURI]; + if (fs == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; + } else { + result = [fs entryForLocalURI:inputURI]; + } + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +//encode path with percent escapes +-(NSString *)encodePath:(NSString *)path +{ + NSString *decodedPath = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //decode incase it's already encoded to avoid encoding twice + return [decodedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; +} + + +/* Part of DirectoryEntry interface, creates or returns the specified directory + * IN: + * NSString* localURI - local filesystem URI for this directory + * NSString* path - directory to be created/returned; may be full path or relative path + * NSDictionary* - Flags object + * boolean as NSNumber create - + * if create is true and directory does not exist, create dir and return directory entry + * if create is true and exclusive is true and directory does exist, return error + * if create is false and directory does not exist, return error + * if create is false and the path represents a file, return error + * boolean as NSNumber exclusive - used in conjunction with create + * if exclusive is true and create is true - specifies failure if directory already exists + * + * + */ +- (void)getDirectory:(CDVInvokedUrlCommand*)command +{ + NSMutableArray* arguments = [NSMutableArray arrayWithArray:command.arguments]; + NSMutableDictionary* options = nil; + + if ([arguments count] >= 3) { + options = [command argumentAtIndex:2 withDefault:nil]; + } + // add getDir to options and call getFile() + if (options != nil) { + options = [NSMutableDictionary dictionaryWithDictionary:options]; + } else { + options = [NSMutableDictionary dictionaryWithCapacity:1]; + } + [options setObject:[NSNumber numberWithInt:1] forKey:@"getDir"]; + if ([arguments count] >= 3) { + [arguments replaceObjectAtIndex:2 withObject:options]; + } else { + [arguments addObject:options]; + } + CDVInvokedUrlCommand* subCommand = + [[CDVInvokedUrlCommand alloc] initWithArguments:arguments + callbackId:command.callbackId + className:command.className + methodName:command.methodName]; + + [self getFile:subCommand]; +} + +/* Part of DirectoryEntry interface, creates or returns the specified file + * IN: + * NSString* baseURI - local filesytem URI for the base directory to search + * NSString* requestedPath - file to be created/returned; may be absolute path or relative path + * NSDictionary* options - Flags object + * boolean as NSNumber create - + * if create is true and file does not exist, create file and return File entry + * if create is true and exclusive is true and file does exist, return error + * if create is false and file does not exist, return error + * if create is false and the path represents a directory, return error + * boolean as NSNumber exclusive - used in conjunction with create + * if exclusive is true and create is true - specifies failure if file already exists + */ +- (void)getFile:(CDVInvokedUrlCommand*)command +{ + NSString* baseURIstr = [command argumentAtIndex:0]; + CDVFilesystemURL* baseURI = [self fileSystemURLforArg:baseURIstr]; + NSString* requestedPath = [command argumentAtIndex:1]; + NSDictionary* options = [command argumentAtIndex:2 withDefault:nil]; + + NSObject *fs = [self filesystemForURL:baseURI]; + CDVPluginResult* result = [fs getFileForURL:baseURI requestedPath:requestedPath options:options]; + + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* + * Look up the parent Entry containing this Entry. + * If this Entry is the root of its filesystem, its parent is itself. + * IN: + * NSArray* arguments + * 0 - NSString* localURI + * NSMutableDictionary* options + * empty + */ +- (void)getParent:(CDVInvokedUrlCommand*)command +{ + // arguments are URL encoded + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + + NSObject *fs = [self filesystemForURL:localURI]; + CDVPluginResult* result = [fs getParentForURL:localURI]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* + * set MetaData of entry + * Currently we only support "com.apple.MobileBackup" (boolean) + */ +- (void)setMetadata:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSDictionary* options = [command argumentAtIndex:1 withDefault:nil]; + NSObject *fs = [self filesystemForURL:localURI]; + CDVPluginResult* result = [fs setMetadataForURL:localURI withObject:options]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* removes the directory or file entry + * IN: + * NSArray* arguments + * 0 - NSString* localURI + * + * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir + * returns INVALID_MODIFICATION_ERR if is non-empty dir or asset library file + * returns NOT_FOUND_ERR if file or dir is not found +*/ +- (void)remove:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + CDVPluginResult* result = nil; + + if ([localURI.fullPath isEqualToString:@""]) { + // error if try to remove top level (documents or tmp) dir + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; + } else { + NSObject *fs = [self filesystemForURL:localURI]; + result = [fs removeFileAtURL:localURI]; + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* recursively removes the directory + * IN: + * NSArray* arguments + * 0 - NSString* localURI + * + * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir + * returns NOT_FOUND_ERR if file or dir is not found + */ +- (void)removeRecursively:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + CDVPluginResult* result = nil; + + if ([localURI.fullPath isEqualToString:@""]) { + // error if try to remove top level (documents or tmp) dir + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; + } else { + NSObject *fs = [self filesystemForURL:localURI]; + result = [fs recursiveRemoveFileAtURL:localURI]; + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +- (void)copyTo:(CDVInvokedUrlCommand*)command +{ + [self doCopyMove:command isCopy:YES]; +} + +- (void)moveTo:(CDVInvokedUrlCommand*)command +{ + [self doCopyMove:command isCopy:NO]; +} + +/* Copy/move a file or directory to a new location + * IN: + * NSArray* arguments + * 0 - NSString* URL of entry to copy + * 1 - NSString* URL of the directory into which to copy/move the entry + * 2 - Optionally, the new name of the entry, defaults to the current name + * BOOL - bCopy YES if copy, NO if move + */ +- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy +{ + NSArray* arguments = command.arguments; + + // arguments + NSString* srcURLstr = [command argumentAtIndex:0]; + NSString* destURLstr = [command argumentAtIndex:1]; + + CDVPluginResult *result; + + if (!srcURLstr || !destURLstr) { + // either no source or no destination provided + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + + CDVFilesystemURL* srcURL = [self fileSystemURLforArg:srcURLstr]; + CDVFilesystemURL* destURL = [self fileSystemURLforArg:destURLstr]; + + NSObject *srcFs = [self filesystemForURL:srcURL]; + NSObject *destFs = [self filesystemForURL:destURL]; + + // optional argument; use last component from srcFullPath if new name not provided + NSString* newName = ([arguments count] > 2) ? [command argumentAtIndex:2] : [srcURL.url lastPathComponent]; + if ([newName rangeOfString:@":"].location != NSNotFound) { + // invalid chars in new name + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + + __weak CDVFile* weakSelf = self; + [self.commandDelegate runInBackground:^ { + [destFs copyFileToURL:destURL withName:newName fromFileSystem:srcFs atURL:srcURL copy:bCopy callback:^(CDVPluginResult* result) { + [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; + +} + +- (void)getFileMetadata:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSObject *fs = [self filesystemForURL:localURI]; + __weak CDVFile* weakSelf = self; + [fs getFileMetadataForURL:localURI callback:^(CDVPluginResult* result) { + [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; +} + +- (void)readEntries:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSObject *fs = [self filesystemForURL:localURI]; + CDVPluginResult *result = [fs readEntriesAtURL:localURI]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* read and return file data + * IN: + * NSArray* arguments + * 0 - NSString* fullPath + * 1 - NSString* encoding + * 2 - NSString* start + * 3 - NSString* end + */ +- (void)readAsText:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSString* encoding = [command argumentAtIndex:1]; + NSInteger start = [[command argumentAtIndex:2] integerValue]; + NSInteger end = [[command argumentAtIndex:3] integerValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + if (fs == nil) { + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + + // TODO: implement + if ([@"UTF-8" caseInsensitiveCompare : encoding] != NSOrderedSame) { + NSLog(@"Only UTF-8 encodings are currently supported by readAsText"); + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + + __weak CDVFile* weakSelf = self; + + [self.commandDelegate runInBackground:^ { + [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + NSString* str = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSUTF8StringEncoding freeWhenDone:NO]; + // Check that UTF8 conversion did not fail. + if (str != nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:str]; + result.associatedObject = data; + } else { + errorCode = ENCODING_ERR; + } + } + if (result == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + + [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; +} + +/* Read content of text file and return as base64 encoded data url. + * IN: + * NSArray* arguments + * 0 - NSString* fullPath + * 1 - NSString* start + * 2 - NSString* end + * + * Determines the mime type from the file extension, returns ENCODING_ERR if mimetype can not be determined. + */ + +- (void)readAsDataURL:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSInteger start = [[command argumentAtIndex:1] integerValue]; + NSInteger end = [[command argumentAtIndex:2] integerValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + __weak CDVFile* weakSelf = self; + [self.commandDelegate runInBackground:^ { + [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + NSString* b64Str = toBase64(data); + NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, b64Str]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + + [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; +} + +/* Read content of text file and return as an arraybuffer + * IN: + * NSArray* arguments + * 0 - NSString* fullPath + * 1 - NSString* start + * 2 - NSString* end + */ + +- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSInteger start = [[command argumentAtIndex:1] integerValue]; + NSInteger end = [[command argumentAtIndex:2] integerValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + __weak CDVFile* weakSelf = self; + + [self.commandDelegate runInBackground:^ { + [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + + [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; +} + +- (void)readAsBinaryString:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSInteger start = [[command argumentAtIndex:1] integerValue]; + NSInteger end = [[command argumentAtIndex:2] integerValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + __weak CDVFile* weakSelf = self; + + [self.commandDelegate runInBackground:^ { + [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + NSString* payload = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSASCIIStringEncoding freeWhenDone:NO]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload]; + result.associatedObject = data; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + + [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; +} + + +- (void)truncate:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + unsigned long long pos = (unsigned long long)[[command argumentAtIndex:1] longLongValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + CDVPluginResult *result = [fs truncateFileAtURL:localURI atPosition:pos]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* write + * IN: + * NSArray* arguments + * 0 - NSString* localURI of file to write to + * 1 - NSString* or NSData* data to write + * 2 - NSNumber* position to begin writing + */ +- (void)write:(CDVInvokedUrlCommand*)command +{ + __weak CDVFile* weakSelf = self; + + [self.commandDelegate runInBackground:^ { + NSString* callbackId = command.callbackId; + + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + id argData = [command argumentAtIndex:1]; + unsigned long long pos = (unsigned long long)[[command argumentAtIndex:2] longLongValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + + [fs truncateFileAtURL:localURI atPosition:pos]; + CDVPluginResult *result; + if ([argData isKindOfClass:[NSString class]]) { + NSData *encData = [argData dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; + result = [fs writeToFileAtURL:localURI withData:encData append:YES]; + } else if ([argData isKindOfClass:[NSData class]]) { + result = [fs writeToFileAtURL:localURI withData:argData append:YES]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Invalid parameter type"]; + } + [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; + }]; +} + +#pragma mark Methods for converting between URLs and paths + +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)localURL +{ + for (NSObject *fs in self.fileSystems) { + if ([fs.name isEqualToString:localURL.fileSystemName]) { + if ([fs respondsToSelector:@selector(filesystemPathForURL:)]) { + return [fs filesystemPathForURL:localURL]; + } + } + } + return nil; +} + +#pragma mark Undocumented Filesystem API + +- (void)testFileExists:(CDVInvokedUrlCommand*)command +{ + // arguments + NSString* argPath = [command argumentAtIndex:0]; + + // Get the file manager + NSFileManager* fMgr = [NSFileManager defaultManager]; + NSString* appFile = argPath; // [ self getFullPath: argPath]; + + BOOL bExists = [fMgr fileExistsAtPath:appFile]; + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1 : 0)]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command +{ + // arguments + NSString* argPath = [command argumentAtIndex:0]; + + // Get the file manager + NSFileManager* fMgr = [[NSFileManager alloc] init]; + NSString* appFile = argPath; // [self getFullPath: argPath]; + BOOL bIsDir = NO; + BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory:&bIsDir]; + + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1 : 0)]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +// Returns number of bytes available via callback +- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command +{ + // no arguments + + NSNumber* pNumAvail = [self checkFreeDiskSpace:self.rootDocsPath]; + + NSString* strFreeSpace = [NSString stringWithFormat:@"%qu", [pNumAvail unsignedLongLongValue]]; + // NSLog(@"Free space is %@", strFreeSpace ); + + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:strFreeSpace]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +#pragma mark Compatibility with older File API + +- (NSString*)getMimeTypeFromPath:(NSString*)fullPath +{ + return [CDVLocalFilesystem getMimeTypeFromPath:fullPath]; +} + +- (NSDictionary *)getDirectoryEntry:(NSString *)localPath isDirectory:(BOOL)bDirRequest +{ + CDVFilesystemURL *localURL = [self fileSystemURLforLocalPath:localPath]; + return [self makeEntryForPath:localURL.fullPath fileSystemName:localURL.fileSystemName isDirectory:bDirRequest]; +} + +#pragma mark Internal methods for testing +// Internal methods for testing: Get the on-disk location of a local filesystem url. +// [Currently used for testing file-transfer] + +- (void)_getLocalFilesystemPath:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURL = [self fileSystemURLforArg:command.arguments[0]]; + + NSString* fsPath = [self filesystemPathForURL:localURL]; + CDVPluginResult* result; + if (fsPath) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:fsPath]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Cannot resolve URL to a file"]; + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +@end diff --git a/mobile/plugins/cordova-plugin-file/src/ios/CDVLocalFilesystem.h b/mobile/plugins/cordova-plugin-file/src/ios/CDVLocalFilesystem.h new file mode 100644 index 0000000..a0186c8 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/ios/CDVLocalFilesystem.h @@ -0,0 +1,32 @@ +/* + 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. + */ + +#import "CDVFile.h" + +@interface CDVLocalFilesystem : NSObject { + NSString *_name; + NSString *_fsRoot; +} + +- (id) initWithName:(NSString *)name root:(NSString *)fsRoot; ++ (NSString*)getMimeTypeFromPath:(NSString*)fullPath; + +@property (nonatomic,strong) NSString *fsRoot; + +@end diff --git a/mobile/plugins/cordova-plugin-file/src/ios/CDVLocalFilesystem.m b/mobile/plugins/cordova-plugin-file/src/ios/CDVLocalFilesystem.m new file mode 100644 index 0000000..35c8db1 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/ios/CDVLocalFilesystem.m @@ -0,0 +1,734 @@ +/* + 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. + */ + +#import "CDVFile.h" +#import "CDVLocalFilesystem.h" +#import +#import +#import + +@implementation CDVLocalFilesystem +@synthesize name=_name, fsRoot=_fsRoot, urlTransformer; + +- (id) initWithName:(NSString *)name root:(NSString *)fsRoot +{ + if (self) { + self.name = name; + self.fsRoot = fsRoot; + } + return self; +} + +/* + * IN + * NSString localURI + * OUT + * CDVPluginResult result containing a file or directoryEntry for the localURI, or an error if the + * URI represents a non-existent path, or is unrecognized or otherwise malformed. + */ +- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url +{ + CDVPluginResult* result = nil; + NSDictionary* entry = [self makeEntryForLocalURL:url]; + if (entry) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:entry]; + } else { + // return NOT_FOUND_ERR + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + } + return result; +} +- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url { + NSString *path = [self filesystemPathForURL:url]; + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + BOOL isDir = NO; + // see if exists and is file or dir + BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&isDir]; + if (bExists) { + return [self makeEntryForPath:url.fullPath isDirectory:isDir]; + } else { + return nil; + } +} +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir +{ + NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5]; + NSString* lastPart = [[self stripQueryParametersFromPath:fullPath] lastPathComponent]; + if (isDir && ![fullPath hasSuffix:@"/"]) { + fullPath = [fullPath stringByAppendingString:@"/"]; + } + [dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"]; + [dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"]; + [dirEntry setObject:fullPath forKey:@"fullPath"]; + [dirEntry setObject:lastPart forKey:@"name"]; + [dirEntry setObject:self.name forKey: @"filesystemName"]; + + NSURL* nativeURL = [NSURL fileURLWithPath:[self filesystemPathForFullPath:fullPath]]; + if (self.urlTransformer) { + nativeURL = self.urlTransformer(nativeURL); + } + + dirEntry[@"nativeURL"] = [nativeURL absoluteString]; + + return dirEntry; +} + +- (NSString *)stripQueryParametersFromPath:(NSString *)fullPath +{ + NSRange questionMark = [fullPath rangeOfString:@"?"]; + if (questionMark.location != NSNotFound) { + return [fullPath substringWithRange:NSMakeRange(0,questionMark.location)]; + } + return fullPath; +} + +- (NSString *)filesystemPathForFullPath:(NSString *)fullPath +{ + NSString *path = nil; + NSString *strippedFullPath = [self stripQueryParametersFromPath:fullPath]; + path = [NSString stringWithFormat:@"%@%@", self.fsRoot, strippedFullPath]; + if ([path length] > 1 && [path hasSuffix:@"/"]) { + path = [path substringToIndex:([path length]-1)]; + } + return path; +} +/* + * IN + * NSString localURI + * OUT + * NSString full local filesystem path for the represented file or directory, or nil if no such path is possible + * The file or directory does not necessarily have to exist. nil is returned if the filesystem type is not recognized, + * or if the URL is malformed. + * The incoming URI should be properly escaped (no raw spaces, etc. URI percent-encoding is expected). + */ +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)url +{ + return [self filesystemPathForFullPath:url.fullPath]; +} + +- (CDVFilesystemURL *)URLforFullPath:(NSString *)fullPath +{ + if (fullPath) { + NSString* escapedPath = [fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + if ([fullPath hasPrefix:@"/"]) { + return [CDVFilesystemURL fileSystemURLWithString:[NSString stringWithFormat:@"%@://localhost/%@%@", kCDVFilesystemURLPrefix, self.name, escapedPath]]; + } + return [CDVFilesystemURL fileSystemURLWithString:[NSString stringWithFormat:@"%@://localhost/%@/%@", kCDVFilesystemURLPrefix, self.name, escapedPath]]; + } + return nil; +} + +- (CDVFilesystemURL *)URLforFilesystemPath:(NSString *)path +{ + return [self URLforFullPath:[self fullPathForFileSystemPath:path]]; + +} + +- (NSString *)normalizePath:(NSString *)rawPath +{ + // If this is an absolute path, the first path component will be '/'. Skip it if that's the case + BOOL isAbsolutePath = [rawPath hasPrefix:@"/"]; + if (isAbsolutePath) { + rawPath = [rawPath substringFromIndex:1]; + } + NSMutableArray *components = [NSMutableArray arrayWithArray:[rawPath pathComponents]]; + for (int index = 0; index < [components count]; ++index) { + if ([[components objectAtIndex:index] isEqualToString:@".."]) { + [components removeObjectAtIndex:index]; + if (index > 0) { + [components removeObjectAtIndex:index-1]; + --index; + } + } + } + + if (isAbsolutePath) { + return [NSString stringWithFormat:@"/%@", [components componentsJoinedByString:@"/"]]; + } else { + return [components componentsJoinedByString:@"/"]; + } + + +} + +- (BOOL)valueForKeyIsNumber:(NSDictionary*)dict key:(NSString*)key +{ + BOOL bNumber = NO; + NSObject* value = dict[key]; + if (value) { + bNumber = [value isKindOfClass:[NSNumber class]]; + } + return bNumber; +} + +- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options +{ + CDVPluginResult* result = nil; + BOOL bDirRequest = NO; + BOOL create = NO; + BOOL exclusive = NO; + int errorCode = 0; // !!! risky - no error code currently defined for 0 + + if ([self valueForKeyIsNumber:options key:@"create"]) { + create = [(NSNumber*)[options valueForKey:@"create"] boolValue]; + } + if ([self valueForKeyIsNumber:options key:@"exclusive"]) { + exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue]; + } + if ([self valueForKeyIsNumber:options key:@"getDir"]) { + // this will not exist for calls directly to getFile but will have been set by getDirectory before calling this method + bDirRequest = [(NSNumber*)[options valueForKey:@"getDir"] boolValue]; + } + // see if the requested path has invalid characters - should we be checking for more than just ":"? + if ([requestedPath rangeOfString:@":"].location != NSNotFound) { + errorCode = ENCODING_ERR; + } else { + // Build new fullPath for the requested resource. + // We concatenate the two paths together, and then scan the resulting string to remove + // parent ("..") references. Any parent references at the beginning of the string are + // silently removed. + NSString *combinedPath = [baseURI.fullPath stringByAppendingPathComponent:requestedPath]; + combinedPath = [self normalizePath:combinedPath]; + CDVFilesystemURL* requestedURL = [self URLforFullPath:combinedPath]; + + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + BOOL bIsDir; + BOOL bExists = [fileMgr fileExistsAtPath:[self filesystemPathForURL:requestedURL] isDirectory:&bIsDir]; + if (bExists && (create == NO) && (bIsDir == !bDirRequest)) { + // path exists and is not of requested type - return TYPE_MISMATCH_ERR + errorCode = TYPE_MISMATCH_ERR; + } else if (!bExists && (create == NO)) { + // path does not exist and create is false - return NOT_FOUND_ERR + errorCode = NOT_FOUND_ERR; + } else if (bExists && (create == YES) && (exclusive == YES)) { + // file/dir already exists and exclusive and create are both true - return PATH_EXISTS_ERR + errorCode = PATH_EXISTS_ERR; + } else { + // if bExists and create == YES - just return data + // if bExists and create == NO - just return data + // if !bExists and create == YES - create and return data + BOOL bSuccess = YES; + NSError __autoreleasing* pError = nil; + if (!bExists && (create == YES)) { + if (bDirRequest) { + // create the dir + bSuccess = [fileMgr createDirectoryAtPath:[self filesystemPathForURL:requestedURL] withIntermediateDirectories:NO attributes:nil error:&pError]; + } else { + // create the empty file + bSuccess = [fileMgr createFileAtPath:[self filesystemPathForURL:requestedURL] contents:nil attributes:nil]; + } + } + if (!bSuccess) { + errorCode = ABORT_ERR; + if (pError) { + NSLog(@"error creating directory: %@", [pError localizedDescription]); + } + } else { + // NSLog(@"newly created file/dir (%@) exists: %d", reqFullPath, [fileMgr fileExistsAtPath:reqFullPath]); + // file existed or was created + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:requestedURL.fullPath isDirectory:bDirRequest]]; + } + } // are all possible conditions met? + } + + if (errorCode > 0) { + // create error callback + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + return result; + +} + +- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI +{ + CDVPluginResult* result = nil; + CDVFilesystemURL *newURI = nil; + if ([localURI.fullPath isEqualToString:@""]) { + // return self + newURI = localURI; + } else { + newURI = [CDVFilesystemURL fileSystemURLWithURL:[localURI.url URLByDeletingLastPathComponent]]; /* TODO: UGLY - FIX */ + } + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + BOOL bIsDir; + BOOL bExists = [fileMgr fileExistsAtPath:[self filesystemPathForURL:newURI] isDirectory:&bIsDir]; + if (bExists) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:newURI.fullPath isDirectory:bIsDir]]; + } else { + // invalid path or file does not exist + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + } + return result; +} + +- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options +{ + BOOL ok = NO; + + NSString* filePath = [self filesystemPathForURL:localURI]; + // we only care about this iCloud key for now. + // set to 1/true to skip backup, set to 0/false to back it up (effectively removing the attribute) + NSString* iCloudBackupExtendedAttributeKey = @"com.apple.MobileBackup"; + id iCloudBackupExtendedAttributeValue = [options objectForKey:iCloudBackupExtendedAttributeKey]; + + if ((iCloudBackupExtendedAttributeValue != nil) && [iCloudBackupExtendedAttributeValue isKindOfClass:[NSNumber class]]) { + if (IsAtLeastiOSVersion(@"5.1")) { + NSURL* url = [NSURL fileURLWithPath:filePath]; + NSError* __autoreleasing error = nil; + + ok = [url setResourceValue:[NSNumber numberWithBool:[iCloudBackupExtendedAttributeValue boolValue]] forKey:NSURLIsExcludedFromBackupKey error:&error]; + } else { // below 5.1 (deprecated - only really supported in 5.01) + u_int8_t value = [iCloudBackupExtendedAttributeValue intValue]; + if (value == 0) { // remove the attribute (allow backup, the default) + ok = (removexattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], 0) == 0); + } else { // set the attribute (skip backup) + ok = (setxattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], &value, sizeof(value), 0, 0) == 0); + } + } + } + + if (ok) { + return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else { + return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; + } +} + +/* remove the file or directory (recursively) + * IN: + * NSString* fullPath - the full path to the file or directory to be removed + * NSString* callbackId + * called from remove and removeRecursively - check all pubic api specific error conditions (dir not empty, etc) before calling + */ + +- (CDVPluginResult*)doRemove:(NSString*)fullPath +{ + CDVPluginResult* result = nil; + BOOL bSuccess = NO; + NSError* __autoreleasing pError = nil; + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + + @try { + bSuccess = [fileMgr removeItemAtPath:fullPath error:&pError]; + if (bSuccess) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else { + // see if we can give a useful error + CDVFileError errorCode = ABORT_ERR; + NSLog(@"error removing filesystem entry at %@: %@", fullPath, [pError localizedDescription]); + if ([pError code] == NSFileNoSuchFileError) { + errorCode = NOT_FOUND_ERR; + } else if ([pError code] == NSFileWriteNoPermissionError) { + errorCode = NO_MODIFICATION_ALLOWED_ERR; + } + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + } @catch(NSException* e) { // NSInvalidArgumentException if path is . or .. + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SYNTAX_ERR]; + } + + return result; +} + +- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI +{ + NSString *fileSystemPath = [self filesystemPathForURL:localURI]; + + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + BOOL bIsDir = NO; + BOOL bExists = [fileMgr fileExistsAtPath:fileSystemPath isDirectory:&bIsDir]; + if (!bExists) { + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + } + if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:fileSystemPath error:nil] count] != 0)) { + // dir is not empty + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR]; + } + return [self doRemove:fileSystemPath]; +} + +- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI +{ + NSString *fileSystemPath = [self filesystemPathForURL:localURI]; + return [self doRemove:fileSystemPath]; +} + +/* + * IN + * NSString localURI + * OUT + * NSString full local filesystem path for the represented file or directory, or nil if no such path is possible + * The file or directory does not necessarily have to exist. nil is returned if the filesystem type is not recognized, + * or if the URL is malformed. + * The incoming URI should be properly escaped (no raw spaces, etc. URI percent-encoding is expected). + */ +- (NSString *)fullPathForFileSystemPath:(NSString *)fsPath +{ + if ([fsPath hasPrefix:self.fsRoot]) { + return [fsPath substringFromIndex:[self.fsRoot length]]; + } + return nil; +} + + +- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI +{ + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + NSError* __autoreleasing error = nil; + NSString *fileSystemPath = [self filesystemPathForURL:localURI]; + + NSArray* contents = [fileMgr contentsOfDirectoryAtPath:fileSystemPath error:&error]; + + if (contents) { + NSMutableArray* entries = [NSMutableArray arrayWithCapacity:1]; + if ([contents count] > 0) { + // create an Entry (as JSON) for each file/dir + for (NSString* name in contents) { + // see if is dir or file + NSString* entryPath = [fileSystemPath stringByAppendingPathComponent:name]; + BOOL bIsDir = NO; + [fileMgr fileExistsAtPath:entryPath isDirectory:&bIsDir]; + NSDictionary* entryDict = [self makeEntryForPath:[self fullPathForFileSystemPath:entryPath] isDirectory:bIsDir]; + [entries addObject:entryDict]; + } + } + return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:entries]; + } else { + // assume not found but could check error for more specific error conditions + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + } +} + +- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos +{ + unsigned long long newPos = 0UL; + + NSFileHandle* file = [NSFileHandle fileHandleForWritingAtPath:filePath]; + + if (file) { + [file truncateFileAtOffset:(unsigned long long)pos]; + newPos = [file offsetInFile]; + [file synchronizeFile]; + [file closeFile]; + } + return newPos; +} + +- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos +{ + unsigned long long newPos = [self truncateFile:[self filesystemPathForURL:localURI] atPosition:pos]; + return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)newPos]; +} + +- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend +{ + NSString *filePath = [self filesystemPathForURL:localURL]; + + CDVPluginResult* result = nil; + CDVFileError errCode = INVALID_MODIFICATION_ERR; + int bytesWritten = 0; + + if (filePath) { + NSOutputStream* fileStream = [NSOutputStream outputStreamToFileAtPath:filePath append:shouldAppend]; + if (fileStream) { + NSUInteger len = [encData length]; + if (len == 0) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:(double)len]; + } else { + [fileStream open]; + + bytesWritten = (int)[fileStream write:[encData bytes] maxLength:len]; + + [fileStream close]; + if (bytesWritten > 0) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:bytesWritten]; + // } else { + // can probably get more detailed error info via [fileStream streamError] + // errCode already set to INVALID_MODIFICATION_ERR; + // bytesWritten = 0; // may be set to -1 on error + } + } + } // else fileStream not created return INVALID_MODIFICATION_ERR + } else { + // invalid filePath + errCode = NOT_FOUND_ERR; + } + if (!result) { + // was an error + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; + } + return result; +} + +/** + * Helper function to check to see if the user attempted to copy an entry into its parent without changing its name, + * or attempted to copy a directory into a directory that it contains directly or indirectly. + * + * IN: + * NSString* srcDir + * NSString* destinationDir + * OUT: + * YES copy/ move is allows + * NO move is onto itself + */ +- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest +{ + // This weird test is to determine if we are copying or moving a directory into itself. + // Copy /Documents/myDir to /Documents/myDir-backup is okay but + // Copy /Documents/myDir to /Documents/myDir/backup not okay + BOOL copyOK = YES; + NSRange range = [dest rangeOfString:src]; + + if (range.location != NSNotFound) { + NSRange testRange = {range.length - 1, ([dest length] - range.length)}; + NSRange resultRange = [dest rangeOfString:@"/" options:0 range:testRange]; + if (resultRange.location != NSNotFound) { + copyOK = NO; + } + } + return copyOK; +} + +- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback +{ + NSFileManager *fileMgr = [[NSFileManager alloc] init]; + NSString *destRootPath = [self filesystemPathForURL:destURL]; + BOOL bDestIsDir = NO; + BOOL bDestExists = [fileMgr fileExistsAtPath:destRootPath isDirectory:&bDestIsDir]; + + NSString *newFileSystemPath = [destRootPath stringByAppendingPathComponent:newName]; + NSString *newFullPath = [self fullPathForFileSystemPath:newFileSystemPath]; + + BOOL bNewIsDir = NO; + BOOL bNewExists = [fileMgr fileExistsAtPath:newFileSystemPath isDirectory:&bNewIsDir]; + + CDVPluginResult *result = nil; + int errCode = 0; + + if (!bDestExists) { + // the destination root does not exist + errCode = NOT_FOUND_ERR; + } + + else if ([srcFs isKindOfClass:[CDVLocalFilesystem class]]) { + /* Same FS, we can shortcut with NSFileManager operations */ + NSString *srcFullPath = [srcFs filesystemPathForURL:srcURL]; + + BOOL bSrcIsDir = NO; + BOOL bSrcExists = [fileMgr fileExistsAtPath:srcFullPath isDirectory:&bSrcIsDir]; + + if (!bSrcExists) { + // the source does not exist + errCode = NOT_FOUND_ERR; + } else if ([newFileSystemPath isEqualToString:srcFullPath]) { + // source and destination can not be the same + errCode = INVALID_MODIFICATION_ERR; + } else if (bSrcIsDir && (bNewExists && !bNewIsDir)) { + // can't copy/move dir to file + errCode = INVALID_MODIFICATION_ERR; + } else { // no errors yet + NSError* __autoreleasing error = nil; + BOOL bSuccess = NO; + if (bCopy) { + if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFileSystemPath]) { + // can't copy dir into self + errCode = INVALID_MODIFICATION_ERR; + } else if (bNewExists) { + // the full destination should NOT already exist if a copy + errCode = PATH_EXISTS_ERR; + } else { + bSuccess = [fileMgr copyItemAtPath:srcFullPath toPath:newFileSystemPath error:&error]; + } + } else { // move + // iOS requires that destination must not exist before calling moveTo + // is W3C INVALID_MODIFICATION_ERR error if destination dir exists and has contents + // + if (!bSrcIsDir && (bNewExists && bNewIsDir)) { + // can't move a file to directory + errCode = INVALID_MODIFICATION_ERR; + } else if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFileSystemPath]) { + // can't move a dir into itself + errCode = INVALID_MODIFICATION_ERR; + } else if (bNewExists) { + if (bNewIsDir && ([[fileMgr contentsOfDirectoryAtPath:newFileSystemPath error:NULL] count] != 0)) { + // can't move dir to a dir that is not empty + errCode = INVALID_MODIFICATION_ERR; + newFileSystemPath = nil; // so we won't try to move + } else { + // remove destination so can perform the moveItemAtPath + bSuccess = [fileMgr removeItemAtPath:newFileSystemPath error:NULL]; + if (!bSuccess) { + errCode = INVALID_MODIFICATION_ERR; // is this the correct error? + newFileSystemPath = nil; + } + } + } else if (bNewIsDir && [newFileSystemPath hasPrefix:srcFullPath]) { + // can't move a directory inside itself or to any child at any depth; + errCode = INVALID_MODIFICATION_ERR; + newFileSystemPath = nil; + } + + if (newFileSystemPath != nil) { + bSuccess = [fileMgr moveItemAtPath:srcFullPath toPath:newFileSystemPath error:&error]; + } + } + if (bSuccess) { + // should verify it is there and of the correct type??? + NSDictionary* newEntry = [self makeEntryForPath:newFullPath isDirectory:bSrcIsDir]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry]; + } else { + if (error) { + if (([error code] == NSFileReadUnknownError) || ([error code] == NSFileReadTooLargeError)) { + errCode = NOT_READABLE_ERR; + } else if ([error code] == NSFileWriteOutOfSpaceError) { + errCode = QUOTA_EXCEEDED_ERR; + } else if ([error code] == NSFileWriteNoPermissionError) { + errCode = NO_MODIFICATION_ALLOWED_ERR; + } + } + } + } + } else { + // Need to copy the hard way + [srcFs readFileAtURL:srcURL start:0 end:-1 callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + BOOL bSuccess = [data writeToFile:newFileSystemPath atomically:YES]; + if (bSuccess) { + // should verify it is there and of the correct type??? + NSDictionary* newEntry = [self makeEntryForPath:newFullPath isDirectory:NO]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ABORT_ERR]; + } + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + callback(result); + }]; + return; // Async IO; return without callback. + } + if (result == nil) { + if (!errCode) { + errCode = INVALID_MODIFICATION_ERR; // Catch-all default + } + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errCode]; + } + callback(result); +} + +/* helper function to get the mimeType from the file extension + * IN: + * NSString* fullPath - filename (may include path) + * OUT: + * NSString* the mime type as type/subtype. nil if not able to determine + */ ++ (NSString*)getMimeTypeFromPath:(NSString*)fullPath +{ + NSString* mimeType = nil; + + if (fullPath) { + CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL); + if (typeId) { + mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType); + if (!mimeType) { + // special case for m4a + if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) { + mimeType = @"audio/mp4"; + } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) { + mimeType = @"audio/wav"; + } else if ([[fullPath pathExtension] rangeOfString:@"css"].location != NSNotFound) { + mimeType = @"text/css"; + } + } + CFRelease(typeId); + } + } + return mimeType; +} + +- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback +{ + NSString *path = [self filesystemPathForURL:localURL]; + + NSString* mimeType = [CDVLocalFilesystem getMimeTypeFromPath:path]; + if (mimeType == nil) { + mimeType = @"*/*"; + } + NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:path]; + if (start > 0) { + [file seekToFileOffset:start]; + } + + NSData* readData; + if (end < 0) { + readData = [file readDataToEndOfFile]; + } else { + readData = [file readDataOfLength:(end - start)]; + } + [file closeFile]; + + callback(readData, mimeType, readData != nil ? NO_ERROR : NOT_FOUND_ERR); +} + +- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback +{ + NSString *path = [self filesystemPathForURL:localURL]; + CDVPluginResult *result; + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + + NSError* __autoreleasing error = nil; + NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:path error:&error]; + + if (fileAttrs) { + + // create dictionary of file info + NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5]; + + [fileInfo setObject:localURL.fullPath forKey:@"fullPath"]; + [fileInfo setObject:@"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping + [fileInfo setObject:[path lastPathComponent] forKey:@"name"]; + + // Ensure that directories (and other non-regular files) report size of 0 + unsigned long long size = ([fileAttrs fileType] == NSFileTypeRegular ? [fileAttrs fileSize] : 0); + [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:size] forKey:@"size"]; + + NSDate* modDate = [fileAttrs fileModificationDate]; + if (modDate) { + [fileInfo setObject:[NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000] forKey:@"lastModifiedDate"]; + } + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; + + } else { + // didn't get fileAttribs + CDVFileError errorCode = ABORT_ERR; + NSLog(@"error getting metadata: %@", [error localizedDescription]); + if ([error code] == NSFileNoSuchFileError || [error code] == NSFileReadNoSuchFileError) { + errorCode = NOT_FOUND_ERR; + } + // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode]; + } + + callback(result); +} + +@end diff --git a/mobile/plugins/cordova-plugin-file/src/osx/CDVFile.h b/mobile/plugins/cordova-plugin-file/src/osx/CDVFile.h new file mode 100644 index 0000000..13a9360 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/osx/CDVFile.h @@ -0,0 +1,189 @@ +/* + 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. + */ + +#import +#import + +NSString* const kCDVFilesystemURLPrefix; + +/** +* The default filesystems if non are specified. +*/ +#define CDV_FILESYSTEMS_DEFAULT @"documents,cache,bundle,root" + +/** +* Preference name of the extra filesystems to be "mounted". the following are supported: +* 'bundle' - mounts the application directory +* 'documents' - mounts the users Documents directory (~/Documents) +* 'root' - mounts the root file system +* 'cache' - mounts the caches directory (~/Library/Caches/ *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback; +- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback; +- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback; + +- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url; +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir; + +@property (nonatomic,strong) NSString *name; +@property (nonatomic, copy) NSURL*(^urlTransformer)(NSURL*); + +@optional +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)localURI; +- (CDVFilesystemURL *)URLforFilesystemPath:(NSString *)path; + +@end + +@interface CDVFile : CDVPlugin { + NSString* rootDocsPath; + NSString* appDocsPath; + NSString* appLibraryPath; + NSString* appTempPath; + + NSMutableArray* fileSystems_; + BOOL userHasAllowed; +} + +- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath; +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystemName:(NSString *)fsName isDirectory:(BOOL)isDir; +- (NSDictionary *)makeEntryForURL:(NSURL *)URL; +- (CDVFilesystemURL *)fileSystemURLforLocalPath:(NSString *)localPath; + +- (NSObject *)filesystemForURL:(CDVFilesystemURL *)localURL; + +/* Native Registration API */ +- (void)registerFilesystem:(NSObject *)fs; +- (NSObject *)fileSystemByName:(NSString *)fsName; + +/* Exec API */ +- (void)requestFileSystem:(CDVInvokedUrlCommand*)command; +- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command; +- (void)getDirectory:(CDVInvokedUrlCommand*)command; +- (void)getFile:(CDVInvokedUrlCommand*)command; +- (void)getParent:(CDVInvokedUrlCommand*)command; +- (void)removeRecursively:(CDVInvokedUrlCommand*)command; +- (void)remove:(CDVInvokedUrlCommand*)command; +- (void)copyTo:(CDVInvokedUrlCommand*)command; +- (void)moveTo:(CDVInvokedUrlCommand*)command; +- (void)getFileMetadata:(CDVInvokedUrlCommand*)command; +- (void)readEntries:(CDVInvokedUrlCommand*)command; +- (void)readAsText:(CDVInvokedUrlCommand*)command; +- (void)readAsDataURL:(CDVInvokedUrlCommand*)command; +- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command; +- (void)write:(CDVInvokedUrlCommand*)command; +- (void)testFileExists:(CDVInvokedUrlCommand*)command; +- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command; +- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command; +- (void)truncate:(CDVInvokedUrlCommand*)command; +- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy; + +/* Compatibilty with older File API */ +- (NSString*)getMimeTypeFromPath:(NSString*)fullPath; +- (NSDictionary *)getDirectoryEntry:(NSString *)target isDirectory:(BOOL)bDirRequest; + +/* Conversion between filesystem paths and URLs */ +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)URL; + +/* Internal methods for testing */ +- (void)_getLocalFilesystemPath:(CDVInvokedUrlCommand*)command; + +/** + * local path of the 'documents' file system (~/Documents) + */ +@property (nonatomic, strong) NSString* appDocsPath; + +/** +* local path of the 'applicationStorageDirectory' file system (~/Library/Application Support/) +*/ +@property (nonatomic, strong) NSString* appSupportPath; + +/** +* local path of the 'persistent' file system (~/Library/Application Support//files) +*/ +@property (nonatomic, strong) NSString* appDataPath; + +/** +* local path of the 'documents' file system (~/Documents) +*/ +@property (nonatomic, strong) NSString* appTempPath; + +/** +* local path of the 'cache' file system (~/Library/Caches/) +*/ +@property (nonatomic, strong) NSString* appCachePath; + +/** + * registered file systems + */ +@property (nonatomic, strong) NSMutableArray* fileSystems; + +@property BOOL userHasAllowed; + +@end diff --git a/mobile/plugins/cordova-plugin-file/src/osx/CDVFile.m b/mobile/plugins/cordova-plugin-file/src/osx/CDVFile.m new file mode 100644 index 0000000..75a6001 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/osx/CDVFile.m @@ -0,0 +1,1056 @@ +/* + 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. + */ + +#import "CDVFile.h" +#import "CDVLocalFilesystem.h" +#import + +static NSString* toBase64(NSData* data) { + SEL s1 = NSSelectorFromString(@"cdv_base64EncodedString"); + SEL s2 = NSSelectorFromString(@"base64EncodedString"); + SEL s3 = NSSelectorFromString(@"base64EncodedStringWithOptions:"); + + if ([data respondsToSelector:s1]) { + NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s1]; + return func(data, s1); + } else if ([data respondsToSelector:s2]) { + NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s2]; + return func(data, s2); + } else if ([data respondsToSelector:s3]) { + NSString* (*func)(id, SEL, NSUInteger) = (void *)[data methodForSelector:s3]; + return func(data, s3, 0); + } else { + return nil; + } +} + +CDVFile *filePlugin = nil; + +extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import)); + +#ifndef __IPHONE_5_1 + NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey"; +#endif + +NSString* const kCDVFilesystemURLPrefix = @"cdvfile"; + +@implementation CDVFilesystemURL +@synthesize url=_url; +@synthesize fileSystemName=_fileSystemName; +@synthesize fullPath=_fullPath; + +- (id) initWithString:(NSString *)strURL +{ + if ( self = [super init] ) { + NSURL *decodedURL = [NSURL URLWithString:strURL]; + return [self initWithURL:decodedURL]; + } + return nil; +} + +-(id) initWithURL:(NSURL *)URL +{ + if ( self = [super init] ) { + _url = URL; + _fileSystemName = [self filesystemNameForLocalURI:URL]; + _fullPath = [self fullPathForLocalURI:URL]; + } + return self; +} + +/* + * IN + * NSString localURI + * OUT + * NSString FileSystem Name for this URI, or nil if it is not recognized. + */ +- (NSString *)filesystemNameForLocalURI:(NSURL *)uri +{ + if ([[uri scheme] isEqualToString:kCDVFilesystemURLPrefix] && [[uri host] isEqualToString:@"localhost"]) { + NSArray *pathComponents = [uri pathComponents]; + if (pathComponents != nil && pathComponents.count > 1) { + return [pathComponents objectAtIndex:1]; + } + } + return nil; +} + +/* + * IN + * NSString localURI + * OUT + * NSString fullPath component suitable for an Entry object. + * The incoming URI should be properly escaped. The returned fullPath is unescaped. + */ +- (NSString *)fullPathForLocalURI:(NSURL *)uri +{ + if ([[uri scheme] isEqualToString:kCDVFilesystemURLPrefix] && [[uri host] isEqualToString:@"localhost"]) { + NSString *path = [uri path]; + if ([uri query]) { + path = [NSString stringWithFormat:@"%@?%@", path, [uri query]]; + } + NSRange slashRange = [path rangeOfString:@"/" options:0 range:NSMakeRange(1, path.length-1)]; + if (slashRange.location == NSNotFound) { + return @""; + } + return [path substringFromIndex:slashRange.location]; + } + return nil; +} + ++ (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL +{ + return [[CDVFilesystemURL alloc] initWithString:strURL]; +} + ++ (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL +{ + return [[CDVFilesystemURL alloc] initWithURL:URL]; +} + +- (NSString *)absoluteURL +{ + return [NSString stringWithFormat:@"cdvfile://localhost/%@%@", self.fileSystemName, self.fullPath]; +} + +@end + +@implementation CDVFilesystemURLProtocol + ++ (BOOL)canInitWithRequest:(NSURLRequest*)request +{ + NSURL* url = [request URL]; + return [[url scheme] isEqualToString:kCDVFilesystemURLPrefix]; +} + ++ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request +{ + return request; +} + ++ (BOOL)requestIsCacheEquivalent:(NSURLRequest*)requestA toRequest:(NSURLRequest*)requestB +{ + return [[[requestA URL] resourceSpecifier] isEqualToString:[[requestB URL] resourceSpecifier]]; +} + +- (void)startLoading +{ + CDVFilesystemURL* url = [CDVFilesystemURL fileSystemURLWithURL:[[self request] URL]]; + NSObject *fs = [filePlugin filesystemForURL:url]; + [fs readFileAtURL:url start:0 end:-1 callback:^void(NSData *data, NSString *mimetype, CDVFileError error) { + NSMutableDictionary* responseHeaders = [[NSMutableDictionary alloc] init]; + responseHeaders[@"Cache-Control"] = @"no-cache"; + + if (!error) { + responseHeaders[@"Content-Type"] = mimetype; + NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url.url statusCode:200 HTTPVersion:@"HTTP/1.1"headerFields:responseHeaders]; + [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + [[self client] URLProtocol:self didLoadData:data]; + [[self client] URLProtocolDidFinishLoading:self]; + } else { + NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url.url statusCode:404 HTTPVersion:@"HTTP/1.1"headerFields:responseHeaders]; + [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + [[self client] URLProtocolDidFinishLoading:self]; + } + }]; +} + +- (void)stopLoading +{} + +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection + willCacheResponse:(NSCachedURLResponse*)cachedResponse { + return nil; +} + +@end + + +@implementation CDVFile + +@synthesize appDocsPath, appDataPath, appSupportPath, appTempPath, appCachePath, userHasAllowed, fileSystems=fileSystems_; + +- (void)registerFilesystem:(NSObject *)fs { + __weak CDVFile* weakSelf = self; + SEL sel = NSSelectorFromString(@"urlTransformer"); + // for backwards compatibility - we check if this property is there + // we create a wrapper block because the urlTransformer property + // on the commandDelegate might be set dynamically at a future time + // (and not dependent on plugin loading order) + if ([self.commandDelegate respondsToSelector:sel]) { + fs.urlTransformer = ^NSURL*(NSURL* urlToTransform) { + // grab the block from the commandDelegate + NSURL* (^urlTransformer)(NSURL*) = ((id(*)(id, SEL))objc_msgSend)(weakSelf.commandDelegate, sel); + // if block is not null, we call it + if (urlTransformer) { + return urlTransformer(urlToTransform); + } else { // else we return the same url + return urlToTransform; + } + }; + } + [fileSystems_ addObject:fs]; +} + +- (NSObject *)fileSystemByName:(NSString *)fsName +{ + if (self.fileSystems != nil) { + for (NSObject *fs in self.fileSystems) { + if ([fs.name isEqualToString:fsName]) { + return fs; + } + } + } + return nil; + +} + +- (NSObject *)filesystemForURL:(CDVFilesystemURL *)localURL { + if (localURL.fileSystemName == nil) return nil; + @try { + return [self fileSystemByName:localURL.fileSystemName]; + } + @catch (NSException *e) { + return nil; + } +} + +- (NSArray *)getExtraFileSystemsPreference:(NSWindowController *)vc +{ + NSString *filesystemsStr = nil; + if([self.viewController isKindOfClass:[CDVViewController class]]) { + CDVViewController *vc = self.viewController; + NSDictionary *settings = [vc settings]; + filesystemsStr = [settings[CDV_PREF_EXTRA_FILESYSTEM] lowercaseString]; + } + if (!filesystemsStr) { + filesystemsStr = CDV_FILESYSTEMS_DEFAULT; + } + return [filesystemsStr componentsSeparatedByString:@","]; +} + +- (void)makeNonSyncable:(NSString*)path { + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSURL* url = [NSURL fileURLWithPath:path]; + [url setResourceValue: [NSNumber numberWithBool: YES] + forKey: NSURLIsExcludedFromBackupKey error:nil]; + +} + +- (void)registerExtraFileSystems:(NSArray *)filesystems fromAvailableSet:(NSDictionary *)availableFileSystems +{ + NSMutableSet *installedFilesystems = [[NSMutableSet alloc] initWithCapacity:7]; + + /* Register filesystems in order */ + for (NSString *fsName in filesystems) { + if (![installedFilesystems containsObject:fsName]) { + NSString *fsRoot = availableFileSystems[fsName]; + if (fsRoot) { + [filePlugin registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:fsName root:fsRoot]]; + [installedFilesystems addObject:fsName]; + } else { + NSLog(@"Unrecognized extra filesystem identifier: %@", fsName); + } + } + } +} + +- (NSDictionary *)getAvailableFileSystems +{ + return @{ + @"documents": self.appDocsPath, + @"cache": self.appCachePath, + @"bundle": [[NSBundle mainBundle] bundlePath], + @"root": @"/" + }; +} + +- (void)pluginInitialize +{ filePlugin = self; + [NSURLProtocol registerClass:[CDVFilesystemURLProtocol class]]; + + fileSystems_ = [[NSMutableArray alloc] initWithCapacity:3]; + + // Get the Temporary directory path + self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath]; // remove trailing slash from NSTemporaryDirectory() + [self registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:@"temporary" root:self.appTempPath]]; + + // ~/Library/Application Support/ + self.appSupportPath = [self getSupportDirectoryFor:NSApplicationSupportDirectory pathComponents:nil]; + + // ~/Library/Application Support//files + self.appDataPath = [self getSupportDirectoryFor:NSApplicationSupportDirectory pathComponents:@[@"files"]]; + [self registerFilesystem:[[CDVLocalFilesystem alloc] initWithName:@"persistent" root:self.appDataPath]]; + + // ~/Documents/ + self.appDocsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + + // ~/Library/Caches//files + self.appCachePath = [self getSupportDirectoryFor:NSCachesDirectory pathComponents:nil]; + + [self registerExtraFileSystems:[self getExtraFileSystemsPreference:self.viewController] + fromAvailableSet:[self getAvailableFileSystems]]; +} + +- (NSString*) getSupportDirectoryFor: (NSSearchPathDirectory) directory pathComponents: (NSArray*) components { + NSError* error; + NSFileManager* fm = [NSFileManager defaultManager]; + NSURL* supportDir = [fm URLForDirectory:directory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error]; + if (supportDir == nil) { + NSLog(@"unable to get support directory: %@", error); + return nil; + } + + NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier]; + NSURL *dirPath = [supportDir URLByAppendingPathComponent:bundleID]; + for (NSString* pathComponent in components) { + dirPath = [dirPath URLByAppendingPathComponent:pathComponent]; + } + + if (![fm fileExistsAtPath:dirPath.path]) { + if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES attributes:nil error:&error]) { + NSLog(@"unable to create support directory: %@", error); + return nil; + } + } + return dirPath.path; +} + + +- (CDVFilesystemURL *)fileSystemURLforArg:(NSString *)urlArg +{ + CDVFilesystemURL* ret = nil; + if ([urlArg hasPrefix:@"file://"]) { + /* This looks like a file url. Get the path, and see if any handlers recognize it. */ + NSURL *fileURL = [NSURL URLWithString:urlArg]; + NSURL *resolvedFileURL = [fileURL URLByResolvingSymlinksInPath]; + NSString *path = [resolvedFileURL path]; + ret = [self fileSystemURLforLocalPath:path]; + } else { + ret = [CDVFilesystemURL fileSystemURLWithString:urlArg]; + } + return ret; +} + +- (CDVFilesystemURL *)fileSystemURLforLocalPath:(NSString *)localPath +{ + CDVFilesystemURL *localURL = nil; + NSUInteger shortestFullPath = 0; + + // Try all installed filesystems, in order. Return the most match url. + for (id object in self.fileSystems) { + if ([object respondsToSelector:@selector(URLforFilesystemPath:)]) { + CDVFilesystemURL *url = [object URLforFilesystemPath:localPath]; + if (url){ + // A shorter fullPath would imply that the filesystem is a better match for the local path + if (!localURL || ([[url fullPath] length] < shortestFullPath)) { + localURL = url; + shortestFullPath = [[url fullPath] length]; + } + } + } + } + return localURL; +} + +- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath +{ + NSFileManager* fMgr = [[NSFileManager alloc] init]; + + NSError* __autoreleasing pError = nil; + + NSDictionary* pDict = [fMgr attributesOfFileSystemForPath:appPath error:&pError]; + NSNumber* pNumAvail = (NSNumber*)[pDict objectForKey:NSFileSystemFreeSize]; + + return pNumAvail; +} + +/* Request the File System info + * + * IN: + * arguments[0] - type (number as string) + * TEMPORARY = 0, PERSISTENT = 1; + * arguments[1] - size + * + * OUT: + * Dictionary representing FileSystem object + * name - the human readable directory name + * root = DirectoryEntry object + * bool isDirectory + * bool isFile + * string name + * string fullPath + * fileSystem = FileSystem object - !! ignored because creates circular reference !! + */ + +- (void)requestFileSystem:(CDVInvokedUrlCommand*)command +{ + // arguments + NSString* strType = [command argumentAtIndex:0]; + unsigned long long size = [[command argumentAtIndex:1] longLongValue]; + + int type = [strType intValue]; + CDVPluginResult* result = nil; + + if (type > self.fileSystems.count) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR]; + NSLog(@"No filesystem of type requested"); + } else { + NSString* fullPath = @"/"; + // check for avail space for size request + NSNumber* pNumAvail = [self checkFreeDiskSpace:self.appSupportPath]; + // NSLog(@"Free space: %@", [NSString stringWithFormat:@"%qu", [ pNumAvail unsignedLongLongValue ]]); + if (pNumAvail && ([pNumAvail unsignedLongLongValue] < size)) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:QUOTA_EXCEEDED_ERR]; + } else { + NSObject *rootFs = [self.fileSystems objectAtIndex:type]; + if (rootFs == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR]; + NSLog(@"No filesystem of type requested"); + } else { + NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2]; + [fileSystem setObject:rootFs.name forKey:@"name"]; + NSDictionary* dirEntry = [self makeEntryForPath:fullPath fileSystemName:rootFs.name isDirectory:YES]; + [fileSystem setObject:dirEntry forKey:@"root"]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; + } + } + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + + +- (void)requestAllFileSystems:(CDVInvokedUrlCommand*)command +{ + NSMutableArray* ret = [[NSMutableArray alloc] init]; + for (NSObject* root in fileSystems_) { + [ret addObject:[self makeEntryForPath:@"/" fileSystemName:root.name isDirectory:YES]]; + } + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:ret]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +- (void)requestAllPaths:(CDVInvokedUrlCommand*)command +{ + NSDictionary* ret = @{ + @"applicationDirectory": [[NSURL fileURLWithPath:[[NSBundle mainBundle] resourcePath]] absoluteString], + @"applicationStorageDirectory": [[NSURL fileURLWithPath:self.appSupportPath] absoluteString], + @"dataDirectory": [[NSURL fileURLWithPath:self.appDataPath] absoluteString], + @"documentsDirectory": [[NSURL fileURLWithPath:self.appDocsPath] absoluteString], + @"cacheDirectory": [[NSURL fileURLWithPath:self.appCachePath] absoluteString], + @"tempDirectory":[[NSURL fileURLWithPath:self.appTempPath] absoluteString], + @"rootDirectory": @"file:///", + }; + + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:ret]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* Creates and returns a dictionary representing an Entry Object + * + * IN: + * NSString* fullPath of the entry + * int fsType - FileSystem type + * BOOL isDirectory - YES if this is a directory, NO if is a file + * OUT: + * NSDictionary* Entry object + * bool as NSNumber isDirectory + * bool as NSNumber isFile + * NSString* name - last part of path + * NSString* fullPath + * NSString* filesystemName - FileSystem name -- actual filesystem will be created on the JS side if necessary, to avoid + * creating circular reference (FileSystem contains DirectoryEntry which contains FileSystem.....!!) + */ +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystemName:(NSString *)fsName isDirectory:(BOOL)isDir +{ + NSObject *fs = [self fileSystemByName:fsName]; + return [fs makeEntryForPath:fullPath isDirectory:isDir]; +} + +- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)localURL +{ + NSObject *fs = [self filesystemForURL:localURL]; + return [fs makeEntryForLocalURL:localURL]; +} + +- (NSDictionary *)makeEntryForURL:(NSURL *)URL +{ + CDVFilesystemURL* fsURL = [self fileSystemURLforArg:[URL absoluteString]]; + return [self makeEntryForLocalURL:fsURL]; +} + +/* + * Given a URI determine the File System information associated with it and return an appropriate W3C entry object + * IN + * NSString* localURI: Should be an escaped local filesystem URI + * OUT + * Entry object + * bool isDirectory + * bool isFile + * string name + * string fullPath + * fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!! + */ +- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command +{ + // arguments + NSString* localURIstr = [command argumentAtIndex:0]; + CDVPluginResult* result; + + localURIstr = [self encodePath:localURIstr]; //encode path before resolving + CDVFilesystemURL* inputURI = [self fileSystemURLforArg:localURIstr]; + + if (inputURI == nil || inputURI.fileSystemName == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; + } else { + NSObject *fs = [self filesystemForURL:inputURI]; + if (fs == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; + } else { + result = [fs entryForLocalURI:inputURI]; + } + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +//encode path with percent escapes +-(NSString *)encodePath:(NSString *)path +{ + NSString *decodedPath = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //decode incase it's already encoded to avoid encoding twice + return [decodedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; +} + + +/* Part of DirectoryEntry interface, creates or returns the specified directory + * IN: + * NSString* localURI - local filesystem URI for this directory + * NSString* path - directory to be created/returned; may be full path or relative path + * NSDictionary* - Flags object + * boolean as NSNumber create - + * if create is true and directory does not exist, create dir and return directory entry + * if create is true and exclusive is true and directory does exist, return error + * if create is false and directory does not exist, return error + * if create is false and the path represents a file, return error + * boolean as NSNumber exclusive - used in conjunction with create + * if exclusive is true and create is true - specifies failure if directory already exists + * + * + */ +- (void)getDirectory:(CDVInvokedUrlCommand*)command +{ + NSMutableArray* arguments = [NSMutableArray arrayWithArray:command.arguments]; + NSMutableDictionary* options = nil; + + if ([arguments count] >= 3) { + options = [command argumentAtIndex:2 withDefault:nil]; + } + // add getDir to options and call getFile() + if (options != nil) { + options = [NSMutableDictionary dictionaryWithDictionary:options]; + } else { + options = [NSMutableDictionary dictionaryWithCapacity:1]; + } + [options setObject:[NSNumber numberWithInt:1] forKey:@"getDir"]; + if ([arguments count] >= 3) { + [arguments replaceObjectAtIndex:2 withObject:options]; + } else { + [arguments addObject:options]; + } + CDVInvokedUrlCommand* subCommand = + [[CDVInvokedUrlCommand alloc] initWithArguments:arguments + callbackId:command.callbackId + className:command.className + methodName:command.methodName]; + + [self getFile:subCommand]; +} + +/* Part of DirectoryEntry interface, creates or returns the specified file + * IN: + * NSString* baseURI - local filesytem URI for the base directory to search + * NSString* requestedPath - file to be created/returned; may be absolute path or relative path + * NSDictionary* options - Flags object + * boolean as NSNumber create - + * if create is true and file does not exist, create file and return File entry + * if create is true and exclusive is true and file does exist, return error + * if create is false and file does not exist, return error + * if create is false and the path represents a directory, return error + * boolean as NSNumber exclusive - used in conjunction with create + * if exclusive is true and create is true - specifies failure if file already exists + */ +- (void)getFile:(CDVInvokedUrlCommand*)command +{ + NSString* baseURIstr = [command argumentAtIndex:0]; + CDVFilesystemURL* baseURI = [self fileSystemURLforArg:baseURIstr]; + NSString* requestedPath = [command argumentAtIndex:1]; + NSDictionary* options = [command argumentAtIndex:2 withDefault:nil]; + + NSObject *fs = [self filesystemForURL:baseURI]; + CDVPluginResult* result = [fs getFileForURL:baseURI requestedPath:requestedPath options:options]; + + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* + * Look up the parent Entry containing this Entry. + * If this Entry is the root of its filesystem, its parent is itself. + * IN: + * NSArray* arguments + * 0 - NSString* localURI + * NSMutableDictionary* options + * empty + */ +- (void)getParent:(CDVInvokedUrlCommand*)command +{ + // arguments are URL encoded + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + + NSObject *fs = [self filesystemForURL:localURI]; + CDVPluginResult* result = [fs getParentForURL:localURI]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* + * set MetaData of entry + * Currently we only support "com.apple.MobileBackup" (boolean) + */ +- (void)setMetadata:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSDictionary* options = [command argumentAtIndex:1 withDefault:nil]; + NSObject *fs = [self filesystemForURL:localURI]; + CDVPluginResult* result = [fs setMetadataForURL:localURI withObject:options]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* removes the directory or file entry + * IN: + * NSArray* arguments + * 0 - NSString* localURI + * + * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir + * returns INVALID_MODIFICATION_ERR if is non-empty dir or asset library file + * returns NOT_FOUND_ERR if file or dir is not found +*/ +- (void)remove:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + CDVPluginResult* result = nil; + + if ([localURI.fullPath isEqualToString:@""]) { + // error if try to remove top level (documents or tmp) dir + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; + } else { + NSObject *fs = [self filesystemForURL:localURI]; + result = [fs removeFileAtURL:localURI]; + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* recursively removes the directory + * IN: + * NSArray* arguments + * 0 - NSString* localURI + * + * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir + * returns NOT_FOUND_ERR if file or dir is not found + */ +- (void)removeRecursively:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + CDVPluginResult* result = nil; + + if ([localURI.fullPath isEqualToString:@""]) { + // error if try to remove top level (documents or tmp) dir + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; + } else { + NSObject *fs = [self filesystemForURL:localURI]; + result = [fs recursiveRemoveFileAtURL:localURI]; + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +- (void)copyTo:(CDVInvokedUrlCommand*)command +{ + [self doCopyMove:command isCopy:YES]; +} + +- (void)moveTo:(CDVInvokedUrlCommand*)command +{ + [self doCopyMove:command isCopy:NO]; +} + +/* Copy/move a file or directory to a new location + * IN: + * NSArray* arguments + * 0 - NSString* URL of entry to copy + * 1 - NSString* URL of the directory into which to copy/move the entry + * 2 - Optionally, the new name of the entry, defaults to the current name + * BOOL - bCopy YES if copy, NO if move + */ +- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy +{ + NSArray* arguments = command.arguments; + + // arguments + NSString* srcURLstr = [command argumentAtIndex:0]; + NSString* destURLstr = [command argumentAtIndex:1]; + + CDVPluginResult *result; + + if (!srcURLstr || !destURLstr) { + // either no source or no destination provided + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + + CDVFilesystemURL* srcURL = [self fileSystemURLforArg:srcURLstr]; + CDVFilesystemURL* destURL = [self fileSystemURLforArg:destURLstr]; + + NSObject *srcFs = [self filesystemForURL:srcURL]; + NSObject *destFs = [self filesystemForURL:destURL]; + + // optional argument; use last component from srcFullPath if new name not provided + NSString* newName = ([arguments count] > 2) ? [command argumentAtIndex:2] : [srcURL.url lastPathComponent]; + if ([newName rangeOfString:@":"].location != NSNotFound) { + // invalid chars in new name + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + + [destFs copyFileToURL:destURL withName:newName fromFileSystem:srcFs atURL:srcURL copy:bCopy callback:^(CDVPluginResult* result) { + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + +} + +- (void)getFileMetadata:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSObject *fs = [self filesystemForURL:localURI]; + + [fs getFileMetadataForURL:localURI callback:^(CDVPluginResult* result) { + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; +} + +- (void)readEntries:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSObject *fs = [self filesystemForURL:localURI]; + CDVPluginResult *result = [fs readEntriesAtURL:localURI]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* read and return file data + * IN: + * NSArray* arguments + * 0 - NSString* fullPath + * 1 - NSString* encoding + * 2 - NSString* start + * 3 - NSString* end + */ +- (void)readAsText:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSString* encoding = [command argumentAtIndex:1]; + NSInteger start = [[command argumentAtIndex:2] integerValue]; + NSInteger end = [[command argumentAtIndex:3] integerValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + if (fs == nil) { + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + + // TODO: implement + if ([@"UTF-8" caseInsensitiveCompare : encoding] != NSOrderedSame) { + NSLog(@"Only UTF-8 encodings are currently supported by readAsText"); + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + return; + } + + [self.commandDelegate runInBackground:^ { + [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + NSString* str = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSUTF8StringEncoding freeWhenDone:NO]; + // Check that UTF8 conversion did not fail. + if (str != nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:str]; + result.associatedObject = data; + } else { + errorCode = ENCODING_ERR; + } + } + if (result == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; +} + +/* Read content of text file and return as base64 encoded data url. + * IN: + * NSArray* arguments + * 0 - NSString* fullPath + * 1 - NSString* start + * 2 - NSString* end + * + * Determines the mime type from the file extension, returns ENCODING_ERR if mimetype can not be determined. + */ + +- (void)readAsDataURL:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSInteger start = [[command argumentAtIndex:1] integerValue]; + NSInteger end = [[command argumentAtIndex:2] integerValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + [self.commandDelegate runInBackground:^ { + [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + NSString* b64Str = toBase64(data); + NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, b64Str]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; +} + +/* Read content of text file and return as an arraybuffer + * IN: + * NSArray* arguments + * 0 - NSString* fullPath + * 1 - NSString* start + * 2 - NSString* end + */ + +- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSInteger start = [[command argumentAtIndex:1] integerValue]; + NSInteger end = [[command argumentAtIndex:2] integerValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + [self.commandDelegate runInBackground:^ { + [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; +} + +- (void)readAsBinaryString:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + NSInteger start = [[command argumentAtIndex:1] integerValue]; + NSInteger end = [[command argumentAtIndex:2] integerValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + [self.commandDelegate runInBackground:^ { + [fs readFileAtURL:localURI start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + NSString* payload = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSASCIIStringEncoding freeWhenDone:NO]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload]; + result.associatedObject = data; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; + }]; +} + + +- (void)truncate:(CDVInvokedUrlCommand*)command +{ + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + unsigned long long pos = (unsigned long long)[[command argumentAtIndex:1] longLongValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + CDVPluginResult *result = [fs truncateFileAtURL:localURI atPosition:pos]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +/* write + * IN: + * NSArray* arguments + * 0 - NSString* localURI of file to write to + * 1 - NSString* or NSData* data to write + * 2 - NSNumber* position to begin writing + */ +- (void)write:(CDVInvokedUrlCommand*)command +{ + [self.commandDelegate runInBackground:^ { + NSString* callbackId = command.callbackId; + + // arguments + CDVFilesystemURL* localURI = [self fileSystemURLforArg:command.arguments[0]]; + id argData = [command argumentAtIndex:1]; + unsigned long long pos = (unsigned long long)[[command argumentAtIndex:2] longLongValue]; + + NSObject *fs = [self filesystemForURL:localURI]; + + + [fs truncateFileAtURL:localURI atPosition:pos]; + CDVPluginResult *result; + if ([argData isKindOfClass:[NSString class]]) { + NSData *encData = [argData dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; + result = [fs writeToFileAtURL:localURI withData:encData append:YES]; + } else if ([argData isKindOfClass:[NSData class]]) { + result = [fs writeToFileAtURL:localURI withData:argData append:YES]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Invalid parameter type"]; + } + [self.commandDelegate sendPluginResult:result callbackId:callbackId]; + }]; +} + +#pragma mark Methods for converting between URLs and paths + +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)localURL +{ + for (NSObject *fs in self.fileSystems) { + if ([fs.name isEqualToString:localURL.fileSystemName]) { + if ([fs respondsToSelector:@selector(filesystemPathForURL:)]) { + return [fs filesystemPathForURL:localURL]; + } + } + } + return nil; +} + +#pragma mark Undocumented Filesystem API + +- (void)testFileExists:(CDVInvokedUrlCommand*)command +{ + // arguments + NSString* argPath = [command argumentAtIndex:0]; + + // Get the file manager + NSFileManager* fMgr = [NSFileManager defaultManager]; + NSString* appFile = argPath; // [ self getFullPath: argPath]; + + BOOL bExists = [fMgr fileExistsAtPath:appFile]; + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1 : 0)]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command +{ + // arguments + NSString* argPath = [command argumentAtIndex:0]; + + // Get the file manager + NSFileManager* fMgr = [[NSFileManager alloc] init]; + NSString* appFile = argPath; // [self getFullPath: argPath]; + BOOL bIsDir = NO; + BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory:&bIsDir]; + + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1 : 0)]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +// Returns number of bytes available via callback +- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command +{ + // no arguments + + NSNumber* pNumAvail = [self checkFreeDiskSpace:self.appDocsPath]; + + NSString* strFreeSpace = [NSString stringWithFormat:@"%qu", [pNumAvail unsignedLongLongValue]]; + // NSLog(@"Free space is %@", strFreeSpace ); + + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:strFreeSpace]; + + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +#pragma mark Compatibility with older File API + +- (NSString*)getMimeTypeFromPath:(NSString*)fullPath +{ + return [CDVLocalFilesystem getMimeTypeFromPath:fullPath]; +} + +- (NSDictionary *)getDirectoryEntry:(NSString *)localPath isDirectory:(BOOL)bDirRequest +{ + CDVFilesystemURL *localURL = [self fileSystemURLforLocalPath:localPath]; + return [self makeEntryForPath:localURL.fullPath fileSystemName:localURL.fileSystemName isDirectory:bDirRequest]; +} + +#pragma mark Internal methods for testing +// Internal methods for testing: Get the on-disk location of a local filesystem url. +// [Currently used for testing file-transfer] + +- (void)_getLocalFilesystemPath:(CDVInvokedUrlCommand*)command +{ + CDVFilesystemURL* localURL = [self fileSystemURLforArg:command.arguments[0]]; + + NSString* fsPath = [self filesystemPathForURL:localURL]; + CDVPluginResult* result; + if (fsPath) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:fsPath]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Cannot resolve URL to a file"]; + } + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; +} + +@end diff --git a/mobile/plugins/cordova-plugin-file/src/osx/CDVLocalFilesystem.h b/mobile/plugins/cordova-plugin-file/src/osx/CDVLocalFilesystem.h new file mode 100644 index 0000000..a0186c8 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/osx/CDVLocalFilesystem.h @@ -0,0 +1,32 @@ +/* + 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. + */ + +#import "CDVFile.h" + +@interface CDVLocalFilesystem : NSObject { + NSString *_name; + NSString *_fsRoot; +} + +- (id) initWithName:(NSString *)name root:(NSString *)fsRoot; ++ (NSString*)getMimeTypeFromPath:(NSString*)fullPath; + +@property (nonatomic,strong) NSString *fsRoot; + +@end diff --git a/mobile/plugins/cordova-plugin-file/src/osx/CDVLocalFilesystem.m b/mobile/plugins/cordova-plugin-file/src/osx/CDVLocalFilesystem.m new file mode 100644 index 0000000..016e399 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/osx/CDVLocalFilesystem.m @@ -0,0 +1,733 @@ +/* + 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. + */ + +#import "CDVFile.h" +#import "CDVLocalFilesystem.h" +#import + +@implementation CDVLocalFilesystem +@synthesize name=_name, fsRoot=_fsRoot, urlTransformer; + +- (id) initWithName:(NSString *)name root:(NSString *)fsRoot +{ + if (self) { + _name = name; + _fsRoot = fsRoot; + } + return self; +} + +/* + * IN + * NSString localURI + * OUT + * CDVPluginResult result containing a file or directoryEntry for the localURI, or an error if the + * URI represents a non-existent path, or is unrecognized or otherwise malformed. + */ +- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url +{ + CDVPluginResult* result = nil; + NSDictionary* entry = [self makeEntryForLocalURL:url]; + if (entry) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:entry]; + } else { + // return NOT_FOUND_ERR + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + } + return result; +} +- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url { + NSString *path = [self filesystemPathForURL:url]; + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + BOOL isDir = NO; + // see if exists and is file or dir + BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&isDir]; + if (bExists) { + return [self makeEntryForPath:url.fullPath isDirectory:isDir]; + } else { + return nil; + } +} +- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir +{ + NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5]; + NSString* lastPart = [[self stripQueryParametersFromPath:fullPath] lastPathComponent]; + if (isDir && ![fullPath hasSuffix:@"/"]) { + fullPath = [fullPath stringByAppendingString:@"/"]; + } + [dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"]; + [dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"]; + [dirEntry setObject:fullPath forKey:@"fullPath"]; + [dirEntry setObject:lastPart forKey:@"name"]; + [dirEntry setObject:self.name forKey: @"filesystemName"]; + + NSURL* nativeURL = [NSURL fileURLWithPath:[self filesystemPathForFullPath:fullPath]]; + if (self.urlTransformer) { + nativeURL = self.urlTransformer(nativeURL); + } + + dirEntry[@"nativeURL"] = [nativeURL absoluteString]; + + return dirEntry; +} + +- (NSString *)stripQueryParametersFromPath:(NSString *)fullPath +{ + NSRange questionMark = [fullPath rangeOfString:@"?"]; + if (questionMark.location != NSNotFound) { + return [fullPath substringWithRange:NSMakeRange(0,questionMark.location)]; + } + return fullPath; +} + +- (NSString *)filesystemPathForFullPath:(NSString *)fullPath +{ + NSString *path = nil; + NSString *strippedFullPath = [self stripQueryParametersFromPath:fullPath]; + path = [NSString stringWithFormat:@"%@%@", self.fsRoot, strippedFullPath]; + if ([path length] > 1 && [path hasSuffix:@"/"]) { + path = [path substringToIndex:([path length]-1)]; + } + return path; +} +/* + * IN + * NSString localURI + * OUT + * NSString full local filesystem path for the represented file or directory, or nil if no such path is possible + * The file or directory does not necessarily have to exist. nil is returned if the filesystem type is not recognized, + * or if the URL is malformed. + * The incoming URI should be properly escaped (no raw spaces, etc. URI percent-encoding is expected). + */ +- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)url +{ + return [self filesystemPathForFullPath:url.fullPath]; +} + +- (CDVFilesystemURL *)URLforFullPath:(NSString *)fullPath +{ + if (fullPath) { + NSString* escapedPath = [fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + if ([fullPath hasPrefix:@"/"]) { + return [CDVFilesystemURL fileSystemURLWithString:[NSString stringWithFormat:@"%@://localhost/%@%@", kCDVFilesystemURLPrefix, self.name, escapedPath]]; + } + return [CDVFilesystemURL fileSystemURLWithString:[NSString stringWithFormat:@"%@://localhost/%@/%@", kCDVFilesystemURLPrefix, self.name, escapedPath]]; + } + return nil; +} + +- (CDVFilesystemURL *)URLforFilesystemPath:(NSString *)path +{ + return [self URLforFullPath:[self fullPathForFileSystemPath:path]]; + +} + +- (NSString *)normalizePath:(NSString *)rawPath +{ + // If this is an absolute path, the first path component will be '/'. Skip it if that's the case + BOOL isAbsolutePath = [rawPath hasPrefix:@"/"]; + if (isAbsolutePath) { + rawPath = [rawPath substringFromIndex:1]; + } + NSMutableArray *components = [NSMutableArray arrayWithArray:[rawPath pathComponents]]; + for (int index = 0; index < [components count]; ++index) { + if ([[components objectAtIndex:index] isEqualToString:@".."]) { + [components removeObjectAtIndex:index]; + if (index > 0) { + [components removeObjectAtIndex:index-1]; + --index; + } + } + } + + if (isAbsolutePath) { + return [NSString stringWithFormat:@"/%@", [components componentsJoinedByString:@"/"]]; + } else { + return [components componentsJoinedByString:@"/"]; + } + + +} + +- (BOOL)valueForKeyIsNumber:(NSDictionary*)dict key:(NSString*)key +{ + BOOL bNumber = NO; + NSObject* value = dict[key]; + if (value) { + bNumber = [value isKindOfClass:[NSNumber class]]; + } + return bNumber; +} + +- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options +{ + CDVPluginResult* result = nil; + BOOL bDirRequest = NO; + BOOL create = NO; + BOOL exclusive = NO; + int errorCode = 0; // !!! risky - no error code currently defined for 0 + + if ([self valueForKeyIsNumber:options key:@"create"]) { + create = [(NSNumber*)[options valueForKey:@"create"] boolValue]; + } + if ([self valueForKeyIsNumber:options key:@"exclusive"]) { + exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue]; + } + if ([self valueForKeyIsNumber:options key:@"getDir"]) { + // this will not exist for calls directly to getFile but will have been set by getDirectory before calling this method + bDirRequest = [(NSNumber*)[options valueForKey:@"getDir"] boolValue]; + } + // see if the requested path has invalid characters - should we be checking for more than just ":"? + if ([requestedPath rangeOfString:@":"].location != NSNotFound) { + errorCode = ENCODING_ERR; + } else { + // Build new fullPath for the requested resource. + // We concatenate the two paths together, and then scan the resulting string to remove + // parent ("..") references. Any parent references at the beginning of the string are + // silently removed. + NSString *combinedPath = [baseURI.fullPath stringByAppendingPathComponent:requestedPath]; + combinedPath = [self normalizePath:combinedPath]; + CDVFilesystemURL* requestedURL = [self URLforFullPath:combinedPath]; + + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + BOOL bIsDir; + BOOL bExists = [fileMgr fileExistsAtPath:[self filesystemPathForURL:requestedURL] isDirectory:&bIsDir]; + if (bExists && (create == NO) && (bIsDir == !bDirRequest)) { + // path exists and is not of requested type - return TYPE_MISMATCH_ERR + errorCode = TYPE_MISMATCH_ERR; + } else if (!bExists && (create == NO)) { + // path does not exist and create is false - return NOT_FOUND_ERR + errorCode = NOT_FOUND_ERR; + } else if (bExists && (create == YES) && (exclusive == YES)) { + // file/dir already exists and exclusive and create are both true - return PATH_EXISTS_ERR + errorCode = PATH_EXISTS_ERR; + } else { + // if bExists and create == YES - just return data + // if bExists and create == NO - just return data + // if !bExists and create == YES - create and return data + BOOL bSuccess = YES; + NSError __autoreleasing* pError = nil; + if (!bExists && (create == YES)) { + if (bDirRequest) { + // create the dir + bSuccess = [fileMgr createDirectoryAtPath:[self filesystemPathForURL:requestedURL] withIntermediateDirectories:NO attributes:nil error:&pError]; + } else { + // create the empty file + bSuccess = [fileMgr createFileAtPath:[self filesystemPathForURL:requestedURL] contents:nil attributes:nil]; + } + } + if (!bSuccess) { + errorCode = ABORT_ERR; + if (pError) { + NSLog(@"error creating directory: %@", [pError localizedDescription]); + } + } else { + // NSLog(@"newly created file/dir (%@) exists: %d", reqFullPath, [fileMgr fileExistsAtPath:reqFullPath]); + // file existed or was created + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:requestedURL.fullPath isDirectory:bDirRequest]]; + } + } // are all possible conditions met? + } + + if (errorCode > 0) { + // create error callback + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + return result; + +} + +- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI +{ + CDVPluginResult* result = nil; + CDVFilesystemURL *newURI = nil; + if ([localURI.fullPath isEqualToString:@""]) { + // return self + newURI = localURI; + } else { + newURI = [CDVFilesystemURL fileSystemURLWithURL:[localURI.url URLByDeletingLastPathComponent]]; /* TODO: UGLY - FIX */ + } + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + BOOL bIsDir; + BOOL bExists = [fileMgr fileExistsAtPath:[self filesystemPathForURL:newURI] isDirectory:&bIsDir]; + if (bExists) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:newURI.fullPath isDirectory:bIsDir]]; + } else { + // invalid path or file does not exist + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + } + return result; +} + +- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options +{ + BOOL ok = NO; + + NSString* filePath = [self filesystemPathForURL:localURI]; + // we only care about this iCloud key for now. + // set to 1/true to skip backup, set to 0/false to back it up (effectively removing the attribute) + NSString* iCloudBackupExtendedAttributeKey = @"com.apple.MobileBackup"; + id iCloudBackupExtendedAttributeValue = [options objectForKey:iCloudBackupExtendedAttributeKey]; + + if ((iCloudBackupExtendedAttributeValue != nil) && [iCloudBackupExtendedAttributeValue isKindOfClass:[NSNumber class]]) { +// todo: fix me +// if (IsAtLeastiOSVersion(@"5.1")) { +// NSURL* url = [NSURL fileURLWithPath:filePath]; +// NSError* __autoreleasing error = nil; +// +// ok = [url setResourceValue:[NSNumber numberWithBool:[iCloudBackupExtendedAttributeValue boolValue]] forKey:NSURLIsExcludedFromBackupKey error:&error]; +// } else { // below 5.1 (deprecated - only really supported in 5.01) +// u_int8_t value = [iCloudBackupExtendedAttributeValue intValue]; +// if (value == 0) { // remove the attribute (allow backup, the default) +// ok = (removexattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], 0) == 0); +// } else { // set the attribute (skip backup) +// ok = (setxattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], &value, sizeof(value), 0, 0) == 0); +// } +// } + } + + if (ok) { + return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else { + return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; + } +} + +/* remove the file or directory (recursively) + * IN: + * NSString* fullPath - the full path to the file or directory to be removed + * NSString* callbackId + * called from remove and removeRecursively - check all pubic api specific error conditions (dir not empty, etc) before calling + */ + +- (CDVPluginResult*)doRemove:(NSString*)fullPath +{ + CDVPluginResult* result = nil; + BOOL bSuccess = NO; + NSError* __autoreleasing pError = nil; + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + + @try { + bSuccess = [fileMgr removeItemAtPath:fullPath error:&pError]; + if (bSuccess) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else { + // see if we can give a useful error + CDVFileError errorCode = ABORT_ERR; + NSLog(@"error removing filesystem entry at %@: %@", fullPath, [pError localizedDescription]); + if ([pError code] == NSFileNoSuchFileError) { + errorCode = NOT_FOUND_ERR; + } else if ([pError code] == NSFileWriteNoPermissionError) { + errorCode = NO_MODIFICATION_ALLOWED_ERR; + } + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + } @catch(NSException* e) { // NSInvalidArgumentException if path is . or .. + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SYNTAX_ERR]; + } + + return result; +} + +- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI +{ + NSString *fileSystemPath = [self filesystemPathForURL:localURI]; + + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + BOOL bIsDir = NO; + BOOL bExists = [fileMgr fileExistsAtPath:fileSystemPath isDirectory:&bIsDir]; + if (!bExists) { + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + } + if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:fileSystemPath error:nil] count] != 0)) { + // dir is not empty + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR]; + } + return [self doRemove:fileSystemPath]; +} + +- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI +{ + NSString *fileSystemPath = [self filesystemPathForURL:localURI]; + return [self doRemove:fileSystemPath]; +} + +/* + * IN + * NSString localURI + * OUT + * NSString full local filesystem path for the represented file or directory, or nil if no such path is possible + * The file or directory does not necessarily have to exist. nil is returned if the filesystem type is not recognized, + * or if the URL is malformed. + * The incoming URI should be properly escaped (no raw spaces, etc. URI percent-encoding is expected). + */ +- (NSString *)fullPathForFileSystemPath:(NSString *)fsPath +{ + if ([fsPath hasPrefix:self.fsRoot]) { + return [fsPath substringFromIndex:[self.fsRoot length]]; + } + return nil; +} + + +- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI +{ + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + NSError* __autoreleasing error = nil; + NSString *fileSystemPath = [self filesystemPathForURL:localURI]; + + NSArray* contents = [fileMgr contentsOfDirectoryAtPath:fileSystemPath error:&error]; + + if (contents) { + NSMutableArray* entries = [NSMutableArray arrayWithCapacity:1]; + if ([contents count] > 0) { + // create an Entry (as JSON) for each file/dir + for (NSString* name in contents) { + // see if is dir or file + NSString* entryPath = [fileSystemPath stringByAppendingPathComponent:name]; + BOOL bIsDir = NO; + [fileMgr fileExistsAtPath:entryPath isDirectory:&bIsDir]; + NSDictionary* entryDict = [self makeEntryForPath:[self fullPathForFileSystemPath:entryPath] isDirectory:bIsDir]; + [entries addObject:entryDict]; + } + } + return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:entries]; + } else { + // assume not found but could check error for more specific error conditions + return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; + } +} + +- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos +{ + unsigned long long newPos = 0UL; + + NSFileHandle* file = [NSFileHandle fileHandleForWritingAtPath:filePath]; + + if (file) { + [file truncateFileAtOffset:(unsigned long long)pos]; + newPos = [file offsetInFile]; + [file synchronizeFile]; + [file closeFile]; + } + return newPos; +} + +- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos +{ + unsigned long long newPos = [self truncateFile:[self filesystemPathForURL:localURI] atPosition:pos]; + return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)newPos]; +} + +- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend +{ + NSString *filePath = [self filesystemPathForURL:localURL]; + + CDVPluginResult* result = nil; + CDVFileError errCode = INVALID_MODIFICATION_ERR; + int bytesWritten = 0; + + if (filePath) { + NSOutputStream* fileStream = [NSOutputStream outputStreamToFileAtPath:filePath append:shouldAppend]; + if (fileStream) { + NSUInteger len = [encData length]; + if (len == 0) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:(double)len]; + } else { + [fileStream open]; + + bytesWritten = (int)[fileStream write:[encData bytes] maxLength:len]; + + [fileStream close]; + if (bytesWritten > 0) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:bytesWritten]; + // } else { + // can probably get more detailed error info via [fileStream streamError] + // errCode already set to INVALID_MODIFICATION_ERR; + // bytesWritten = 0; // may be set to -1 on error + } + } + } // else fileStream not created return INVALID_MODIFICATION_ERR + } else { + // invalid filePath + errCode = NOT_FOUND_ERR; + } + if (!result) { + // was an error + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; + } + return result; +} + +/** + * Helper function to check to see if the user attempted to copy an entry into its parent without changing its name, + * or attempted to copy a directory into a directory that it contains directly or indirectly. + * + * IN: + * NSString* srcDir + * NSString* destinationDir + * OUT: + * YES copy/ move is allows + * NO move is onto itself + */ +- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest +{ + // This weird test is to determine if we are copying or moving a directory into itself. + // Copy /Documents/myDir to /Documents/myDir-backup is okay but + // Copy /Documents/myDir to /Documents/myDir/backup not okay + BOOL copyOK = YES; + NSRange range = [dest rangeOfString:src]; + + if (range.location != NSNotFound) { + NSRange testRange = {range.length - 1, ([dest length] - range.length)}; + NSRange resultRange = [dest rangeOfString:@"/" options:0 range:testRange]; + if (resultRange.location != NSNotFound) { + copyOK = NO; + } + } + return copyOK; +} + +- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback +{ + NSFileManager *fileMgr = [[NSFileManager alloc] init]; + NSString *destRootPath = [self filesystemPathForURL:destURL]; + BOOL bDestIsDir = NO; + BOOL bDestExists = [fileMgr fileExistsAtPath:destRootPath isDirectory:&bDestIsDir]; + + NSString *newFileSystemPath = [destRootPath stringByAppendingPathComponent:newName]; + NSString *newFullPath = [self fullPathForFileSystemPath:newFileSystemPath]; + + BOOL bNewIsDir = NO; + BOOL bNewExists = [fileMgr fileExistsAtPath:newFileSystemPath isDirectory:&bNewIsDir]; + + CDVPluginResult *result = nil; + int errCode = 0; + + if (!bDestExists) { + // the destination root does not exist + errCode = NOT_FOUND_ERR; + } + + else if ([srcFs isKindOfClass:[CDVLocalFilesystem class]]) { + /* Same FS, we can shortcut with NSFileManager operations */ + NSString *srcFullPath = [srcFs filesystemPathForURL:srcURL]; + + BOOL bSrcIsDir = NO; + BOOL bSrcExists = [fileMgr fileExistsAtPath:srcFullPath isDirectory:&bSrcIsDir]; + + if (!bSrcExists) { + // the source does not exist + errCode = NOT_FOUND_ERR; + } else if ([newFileSystemPath isEqualToString:srcFullPath]) { + // source and destination can not be the same + errCode = INVALID_MODIFICATION_ERR; + } else if (bSrcIsDir && (bNewExists && !bNewIsDir)) { + // can't copy/move dir to file + errCode = INVALID_MODIFICATION_ERR; + } else { // no errors yet + NSError* __autoreleasing error = nil; + BOOL bSuccess = NO; + if (bCopy) { + if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFileSystemPath]) { + // can't copy dir into self + errCode = INVALID_MODIFICATION_ERR; + } else if (bNewExists) { + // the full destination should NOT already exist if a copy + errCode = PATH_EXISTS_ERR; + } else { + bSuccess = [fileMgr copyItemAtPath:srcFullPath toPath:newFileSystemPath error:&error]; + } + } else { // move + // iOS requires that destination must not exist before calling moveTo + // is W3C INVALID_MODIFICATION_ERR error if destination dir exists and has contents + // + if (!bSrcIsDir && (bNewExists && bNewIsDir)) { + // can't move a file to directory + errCode = INVALID_MODIFICATION_ERR; + } else if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFileSystemPath]) { + // can't move a dir into itself + errCode = INVALID_MODIFICATION_ERR; + } else if (bNewExists) { + if (bNewIsDir && ([[fileMgr contentsOfDirectoryAtPath:newFileSystemPath error:NULL] count] != 0)) { + // can't move dir to a dir that is not empty + errCode = INVALID_MODIFICATION_ERR; + newFileSystemPath = nil; // so we won't try to move + } else { + // remove destination so can perform the moveItemAtPath + bSuccess = [fileMgr removeItemAtPath:newFileSystemPath error:NULL]; + if (!bSuccess) { + errCode = INVALID_MODIFICATION_ERR; // is this the correct error? + newFileSystemPath = nil; + } + } + } else if (bNewIsDir && [newFileSystemPath hasPrefix:srcFullPath]) { + // can't move a directory inside itself or to any child at any depth; + errCode = INVALID_MODIFICATION_ERR; + newFileSystemPath = nil; + } + + if (newFileSystemPath != nil) { + bSuccess = [fileMgr moveItemAtPath:srcFullPath toPath:newFileSystemPath error:&error]; + } + } + if (bSuccess) { + // should verify it is there and of the correct type??? + NSDictionary* newEntry = [self makeEntryForPath:newFullPath isDirectory:bSrcIsDir]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry]; + } else { + if (error) { + if (([error code] == NSFileReadUnknownError) || ([error code] == NSFileReadTooLargeError)) { + errCode = NOT_READABLE_ERR; + } else if ([error code] == NSFileWriteOutOfSpaceError) { + errCode = QUOTA_EXCEEDED_ERR; + } else if ([error code] == NSFileWriteNoPermissionError) { + errCode = NO_MODIFICATION_ALLOWED_ERR; + } + } + } + } + } else { + // Need to copy the hard way + [srcFs readFileAtURL:srcURL start:0 end:-1 callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { + CDVPluginResult* result = nil; + if (data != nil) { + BOOL bSuccess = [data writeToFile:newFileSystemPath atomically:YES]; + if (bSuccess) { + // should verify it is there and of the correct type??? + NSDictionary* newEntry = [self makeEntryForPath:newFullPath isDirectory:NO]; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry]; + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ABORT_ERR]; + } + } else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; + } + callback(result); + }]; + return; // Async IO; return without callback. + } + if (result == nil) { + if (!errCode) { + errCode = INVALID_MODIFICATION_ERR; // Catch-all default + } + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errCode]; + } + callback(result); +} + +/* helper function to get the mimeType from the file extension + * IN: + * NSString* fullPath - filename (may include path) + * OUT: + * NSString* the mime type as type/subtype. nil if not able to determine + */ ++ (NSString*)getMimeTypeFromPath:(NSString*)fullPath +{ + NSString* mimeType = nil; + + if (fullPath) { + CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL); + if (typeId) { + mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType); + if (!mimeType) { + // special case for m4a + if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) { + mimeType = @"audio/mp4"; + } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) { + mimeType = @"audio/wav"; + } else if ([[fullPath pathExtension] rangeOfString:@"css"].location != NSNotFound) { + mimeType = @"text/css"; + } + } + CFRelease(typeId); + } + } + return mimeType; +} + +- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback +{ + NSString *path = [self filesystemPathForURL:localURL]; + + NSString* mimeType = [CDVLocalFilesystem getMimeTypeFromPath:path]; + if (mimeType == nil) { + mimeType = @"*/*"; + } + NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:path]; + if (start > 0) { + [file seekToFileOffset:start]; + } + + NSData* readData; + if (end < 0) { + readData = [file readDataToEndOfFile]; + } else { + readData = [file readDataOfLength:(end - start)]; + } + [file closeFile]; + + callback(readData, mimeType, readData != nil ? NO_ERROR : NOT_FOUND_ERR); +} + +- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback +{ + NSString *path = [self filesystemPathForURL:localURL]; + CDVPluginResult *result; + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + + NSError* __autoreleasing error = nil; + NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:path error:&error]; + + if (fileAttrs) { + + // create dictionary of file info + NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5]; + + [fileInfo setObject:localURL.fullPath forKey:@"fullPath"]; + [fileInfo setObject:@"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping + [fileInfo setObject:[path lastPathComponent] forKey:@"name"]; + + // Ensure that directories (and other non-regular files) report size of 0 + unsigned long long size = ([fileAttrs fileType] == NSFileTypeRegular ? [fileAttrs fileSize] : 0); + [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:size] forKey:@"size"]; + + NSDate* modDate = [fileAttrs fileModificationDate]; + if (modDate) { + [fileInfo setObject:[NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000] forKey:@"lastModifiedDate"]; + } + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; + + } else { + // didn't get fileAttribs + CDVFileError errorCode = ABORT_ERR; + NSLog(@"error getting metadata: %@", [error localizedDescription]); + if ([error code] == NSFileNoSuchFileError || [error code] == NSFileReadNoSuchFileError) { + errorCode = NOT_FOUND_ERR; + } + // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode]; + } + + callback(result); +} + +@end diff --git a/mobile/plugins/cordova-plugin-file/src/ubuntu/file.cpp b/mobile/plugins/cordova-plugin-file/src/ubuntu/file.cpp new file mode 100644 index 0000000..395ab2d --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/ubuntu/file.cpp @@ -0,0 +1,912 @@ +/* + * Licensed 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. + */ + +#include "file.h" + +#include + +namespace { + class FileError { + public: + static const QString kEncodingErr; + static const QString kTypeMismatchErr; + static const QString kNotFoundErr; + static const QString kSecurityErr; + static const QString kAbortErr; + static const QString kNotReadableErr; + static const QString kNoModificationAllowedErr; + static const QString kInvalidStateErr; + static const QString kSyntaxErr; + static const QString kInvalidModificationErr; + static const QString kQuotaExceededErr; + static const QString kPathExistsErr; + }; + + bool checkFileName(const QString &name) { + if (name.contains(":")){ + return false; + } + return true; + } +}; + +const QString FileError::kEncodingErr("FileError.ENCODING_ERR"); +const QString FileError::kTypeMismatchErr("FileError.TYPE_MISMATCH_ERR"); +const QString FileError::kNotFoundErr("FileError.NOT_FOUND_ERR"); +const QString FileError::kSecurityErr("FileError.SECURITY_ERR"); +const QString FileError::kAbortErr("FileError.ABORT_ERR"); +const QString FileError::kNotReadableErr("FileError.NOT_READABLE_ERR"); +const QString FileError::kNoModificationAllowedErr("FileError.NO_MODIFICATION_ALLOWED_ERR"); +const QString FileError::kInvalidStateErr("FileError.INVALID_STATE_ERR"); +const QString FileError::kSyntaxErr("FileError.SYNTAX_ERR"); +const QString FileError::kInvalidModificationErr("FileError.INVALID_MODIFICATION_ERR"); +const QString FileError::kQuotaExceededErr("FileError.QUOTA_EXCEEDED_ERR"); +const QString FileError::kPathExistsErr("FileError.PATH_EXISTS_ERR"); + +File::File(Cordova *cordova) : + CPlugin(cordova), + _persistentDir(QString("%1/.local/share/%2/persistent").arg(QDir::homePath()).arg(QCoreApplication::applicationName())) { + QDir::root().mkpath(_persistentDir.absolutePath()); +} + +QVariantMap File::file2map(const QFileInfo &fileInfo) { + QVariantMap res; + + res.insert("name", fileInfo.fileName()); + QPair r = GetRelativePath(fileInfo); + res.insert("fullPath", QString("/") + r.second); + res.insert("filesystemName", r.first); + + res.insert("nativeURL", QString("file://localhost") + fileInfo.absoluteFilePath()); + res.insert("isDirectory", (int)fileInfo.isDir()); + res.insert("isFile", (int)fileInfo.isFile()); + + return res; +} + +QVariantMap File::dir2map(const QDir &dir) { + return file2map(QFileInfo(dir.absolutePath())); +} + +QPair File::GetRelativePath(const QFileInfo &fileInfo) { + QString fullPath = fileInfo.isDir() ? QDir::cleanPath(fileInfo.absoluteFilePath()) : fileInfo.absoluteFilePath(); + + QString relativePath1 = _persistentDir.relativeFilePath(fullPath); + QString relativePath2 = QDir::temp().relativeFilePath(fullPath); + + if (!(relativePath1[0] != '.' || relativePath2[0] != '.')) { + if (relativePath1.size() > relativePath2.size()) { + return QPair("temporary", relativePath2); + } else { + return QPair("persistent", relativePath1); + } + } + + if (relativePath1[0] != '.') + return QPair("persistent", relativePath1); + return QPair("temporary", relativePath2); +} + +void File::requestFileSystem(int scId, int ecId, unsigned short type, unsigned long long size) { + QDir dir; + + if (size >= 1000485760){ + this->callback(ecId, FileError::kQuotaExceededErr); + return; + } + + if (type == 0) + dir = QDir::temp(); + else + dir = _persistentDir; + + if (type > 1) { + this->callback(ecId, FileError::kSyntaxErr); + return; + } else { + QVariantMap res; + res.insert("root", dir2map(dir)); + if (type == 0) + res.insert("name", "temporary"); + else + res.insert("name", "persistent"); + + this->cb(scId, res); + } +} + +QPair File::resolveURI(int ecId, const QString &uri) { + QPair result; + + result.first = false; + + QUrl url = QUrl::fromUserInput(uri); + + if (url.scheme() == "file" && url.isValid()) { + result.first = true; + result.second = QFileInfo(url.path()); + return result; + } + + if (url.scheme() != "cdvfile") { + if (ecId) + this->callback(ecId, FileError::kTypeMismatchErr); + return result; + } + + QString path = url.path().replace("//", "/"); + //NOTE: colon is not safe in url, it is not a valid path in Win and Mac, simple disable it here. + if (path.contains(":") || !url.isValid()){ + if (ecId) + this->callback(ecId, FileError::kEncodingErr); + return result; + } + if (!path.startsWith("/persistent/") && !path.startsWith("/temporary/")) { + if (ecId) + this->callback(ecId, FileError::kEncodingErr); + return result; + } + + result.first = true; + if (path.startsWith("/persistent/")) { + QString relativePath = path.mid(QString("/persistent/").size()); + result.second = QFileInfo(_persistentDir.filePath(relativePath)); + } else { + QString relativePath = path.mid(QString("/temporary/").size()); + result.second = QFileInfo(QDir::temp().filePath(relativePath)); + } + return result; +} + +QPair File::resolveURI(const QString &uri) { + return resolveURI(0, uri); +} + + +void File::_getLocalFilesystemPath(int scId, int ecId, const QString& uri) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + this->cb(scId, f1.second.absoluteFilePath()); +} + +void File::resolveLocalFileSystemURI(int scId, int ecId, const QString &uri) { + if (uri[0] == '/' || uri[0] == '.') { + this->callback(ecId, FileError::kEncodingErr); + return; + } + + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + QFileInfo fileInfo = f1.second; + if (!fileInfo.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + this->cb(scId, file2map(fileInfo)); +} + +void File::getFile(int scId, int ecId, const QString &parentPath, const QString &rpath, const QVariantMap &options) { + QPair f1 = resolveURI(ecId, parentPath + "/" + rpath); + if (!f1.first) + return; + + bool create = options.value("create").toBool(); + bool exclusive = options.value("exclusive").toBool(); + QFile file(f1.second.absoluteFilePath()); + + // if create is false and the path represents a directory, return error + QFileInfo fileInfo = f1.second; + if ((!create) && fileInfo.isDir()) { + this->callback(ecId, FileError::kTypeMismatchErr); + return; + } + + // if file does exist, and create is true and exclusive is true, return error + if (file.exists()) { + if (create && exclusive) { + this->callback(ecId, FileError::kPathExistsErr); + return; + } + } + else { + // if file does not exist and create is false, return error + if (!create) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + file.open(QIODevice::WriteOnly); + file.close(); + + // Check if creation was successfull + if (!file.exists()) { + this->callback(ecId, FileError::kNoModificationAllowedErr); + return; + } + } + + this->cb(scId, file2map(QFileInfo(file))); +} + +void File::getDirectory(int scId, int ecId, const QString &parentPath, const QString &rpath, const QVariantMap &options) { + QPair f1 = resolveURI(ecId, parentPath + "/" + rpath); + if (!f1.first) + return; + + bool create = options.value("create").toBool(); + bool exclusive = options.value("exclusive").toBool(); + QDir dir(f1.second.absoluteFilePath()); + + QFileInfo &fileInfo = f1.second; + if ((!create) && fileInfo.isFile()) { + this->callback(ecId, FileError::kTypeMismatchErr); + return; + } + + if (dir.exists()) { + if (create && exclusive) { + this->callback(ecId, FileError::kPathExistsErr); + return; + } + } + else { + if (!create) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + QString folderName = dir.dirName(); + dir.cdUp(); + dir.mkdir(folderName); + dir.cd(folderName); + + if (!dir.exists()) { + this->callback(ecId, FileError::kNoModificationAllowedErr); + return; + } + } + + this->cb(scId, dir2map(dir)); +} + +void File::removeRecursively(int scId, int ecId, const QString &uri) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + QDir dir(f1.second.absoluteFilePath()); + if (File::rmDir(dir)) + this->cb(scId); + else + this->callback(ecId, FileError::kNoModificationAllowedErr); +} + +void File::write(int scId, int ecId, const QString &uri, const QString &_data, unsigned long long position, bool binary) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + QFile file(f1.second.absoluteFilePath()); + + file.open(QIODevice::WriteOnly); + file.close(); + + if (!file.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + QFileInfo fileInfo(file); + if (!file.open(QIODevice::ReadWrite)) { + this->callback(ecId, FileError::kNoModificationAllowedErr); + return; + } + + if (!binary) { + QTextStream textStream(&file); + textStream.setCodec("UTF-8"); + textStream.setAutoDetectUnicode(true); + + if (!textStream.seek(position)) { + file.close(); + fileInfo.refresh(); + + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + textStream << _data; + textStream.flush(); + } else { + QByteArray data(_data.toUtf8()); + if (!file.seek(position)) { + file.close(); + fileInfo.refresh(); + + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + file.write(data.data(), data.length()); + } + + file.flush(); + file.close(); + fileInfo.refresh(); + + this->cb(scId, fileInfo.size() - position); +} + +void File::truncate(int scId, int ecId, const QString &uri, unsigned long long size) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + QFile file(f1.second.absoluteFilePath()); + + if (!file.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + if (!file.resize(size)) { + this->callback(ecId, FileError::kNoModificationAllowedErr); + return; + } + + this->cb(scId, size); +} + +void File::getParent(int scId, int ecId, const QString &uri) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + QDir dir(f1.second.absoluteFilePath()); + + //can't cdup more than app's root + // Try to change into upper directory + if (dir != _persistentDir && dir != QDir::temp()){ + if (!dir.cdUp()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + } + this->cb(scId, dir2map(dir)); +} + +void File::remove(int scId, int ecId, const QString &uri) { + QPair f1 = resolveURI(ecId, uri); + if (!f1.first) + return; + + QFileInfo &fileInfo = f1.second; + //TODO: fix + if (!fileInfo.exists() || (fileInfo.absoluteFilePath() == _persistentDir.absolutePath()) || (QDir::temp() == fileInfo.absoluteFilePath())) { + this->callback(ecId, FileError::kNoModificationAllowedErr); + return; + } + + if (fileInfo.isDir()) { + QDir dir(fileInfo.absoluteFilePath()); + if (dir.rmdir(dir.absolutePath())) { + this->cb(scId); + return; + } + } else { + QFile file(fileInfo.absoluteFilePath()); + if (file.remove()) { + this->cb(scId); + return; + } + } + + this->callback(ecId, FileError::kInvalidModificationErr); +} + +void File::getFileMetadata(int scId, int ecId, const QString &uri) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + QFileInfo &fileInfo = f1.second; + + if (!fileInfo.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + } else { + QMimeType mime = _db.mimeTypeForFile(fileInfo.fileName()); + + QString args = QString("{name: %1, fullPath: %2, type: %3, lastModifiedDate: new Date(%4), size: %5}") + .arg(CordovaInternal::format(fileInfo.fileName())).arg(CordovaInternal::format(fileInfo.absoluteFilePath())) + .arg(CordovaInternal::format(mime.name())).arg(fileInfo.lastModified().toMSecsSinceEpoch()) + .arg(fileInfo.size()); + + this->callback(scId, args); + } +} + +void File::getMetadata(int scId, int ecId, const QString &uri) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + QFileInfo &fileInfo = f1.second; + + if (!fileInfo.exists()) + this->callback(ecId, FileError::kNotFoundErr); + else { + QVariantMap obj; + obj.insert("modificationTime", fileInfo.lastModified().toMSecsSinceEpoch()); + obj.insert("size", fileInfo.isDir() ? 0 : fileInfo.size()); + this->cb(scId, obj); + } +} + +void File::readEntries(int scId, int ecId, const QString &uri) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + QDir dir(f1.second.absoluteFilePath()); + QString entriesList; + + if (!dir.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + for (const QFileInfo &fileInfo: dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) { + entriesList += CordovaInternal::format(file2map(fileInfo)) + ","; + } + // Remove trailing comma + if (entriesList.size() > 0) + entriesList.remove(entriesList.size() - 1, 1); + + entriesList = "new Array(" + entriesList + ")"; + + this->callback(scId, entriesList); +} + +void File::readAsText(int scId, int ecId, const QString &uri, const QString &/*encoding*/, int sliceStart, int sliceEnd) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + QFile file(f1.second.absoluteFilePath()); + + if (!file.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + if (!file.open(QIODevice::ReadOnly)) { + this->callback(ecId, FileError::kNotReadableErr); + return; + } + + QByteArray content = file.readAll(); + + if (sliceEnd == -1) + sliceEnd = content.size(); + if (sliceEnd < 0) { + sliceEnd++; + sliceEnd = std::max(0, content.size() + sliceEnd); + } + if (sliceEnd > content.size()) + sliceEnd = content.size(); + + if (sliceStart < 0) + sliceStart = std::max(0, content.size() + sliceStart); + if (sliceStart > content.size()) + sliceStart = content.size(); + + if (sliceStart > sliceEnd) + sliceEnd = sliceStart; + + //FIXME: encoding + content = content.mid(sliceStart, sliceEnd - sliceStart); + + this->cb(scId, content); +} + +void File::readAsArrayBuffer(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) { + const QString str2array("\ + (function strToArray(str) { \ + var res = new Uint8Array(str.length); \ + for (var i = 0; i < str.length; i++) { \ + res[i] = str.charCodeAt(i); \ + } \ + return res; \ + })(\"%1\")"); + + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + QFile file(f1.second.absoluteFilePath()); + + if (!file.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + if (!file.open(QIODevice::ReadOnly)) { + this->callback(ecId, FileError::kNotReadableErr); + return; + } + QString res; + QByteArray content = file.readAll(); + + if (sliceEnd == -1) + sliceEnd = content.size(); + if (sliceEnd < 0) { + sliceEnd++; + sliceEnd = std::max(0, content.size() + sliceEnd); + } + if (sliceEnd > content.size()) + sliceEnd = content.size(); + + if (sliceStart < 0) + sliceStart = std::max(0, content.size() + sliceStart); + if (sliceStart > content.size()) + sliceStart = content.size(); + + if (sliceStart > sliceEnd) + sliceEnd = sliceStart; + + content = content.mid(sliceStart, sliceEnd - sliceStart); + + res.reserve(content.length() * 6); + for (uchar c: content) { + res += "\\x"; + res += QString::number(c, 16).rightJustified(2, '0').toUpper(); + } + + this->callback(scId, str2array.arg(res)); +} + +void File::readAsBinaryString(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + QFile file(f1.second.absoluteFilePath()); + + if (!file.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + if (!file.open(QIODevice::ReadOnly)) { + this->callback(ecId, FileError::kNotReadableErr); + return; + } + QString res; + QByteArray content = file.readAll(); + + if (sliceEnd == -1) + sliceEnd = content.size(); + if (sliceEnd < 0) { + sliceEnd++; + sliceEnd = std::max(0, content.size() + sliceEnd); + } + if (sliceEnd > content.size()) + sliceEnd = content.size(); + + if (sliceStart < 0) + sliceStart = std::max(0, content.size() + sliceStart); + if (sliceStart > content.size()) + sliceStart = content.size(); + + if (sliceStart > sliceEnd) + sliceEnd = sliceStart; + + content = content.mid(sliceStart, sliceEnd - sliceStart); + + res.reserve(content.length() * 6); + for (uchar c: content) { + res += "\\x"; + res += QString::number(c, 16).rightJustified(2, '0').toUpper(); + } + this->callback(scId, "\"" + res + "\""); +} + +void File::readAsDataURL(int scId, int ecId, const QString &uri, int sliceStart, int sliceEnd) { + QPair f1 = resolveURI(ecId, uri); + + if (!f1.first) + return; + + QFile file(f1.second.absoluteFilePath()); + QFileInfo &fileInfo = f1.second; + + if (!file.exists()) { + this->callback(ecId, FileError::kNotReadableErr); + return; + } + + if (!file.open(QIODevice::ReadOnly)) { + this->callback(ecId, FileError::kNotReadableErr); + return; + } + + QByteArray content = file.readAll(); + QString contentType(_db.mimeTypeForFile(fileInfo.fileName()).name()); + + if (sliceEnd == -1) + sliceEnd = content.size(); + if (sliceEnd < 0) { + sliceEnd++; + sliceEnd = std::max(0, content.size() + sliceEnd); + } + if (sliceEnd > content.size()) + sliceEnd = content.size(); + + if (sliceStart < 0) + sliceStart = std::max(0, content.size() + sliceStart); + if (sliceStart > content.size()) + sliceStart = content.size(); + + if (sliceStart > sliceEnd) + sliceEnd = sliceStart; + + content = content.mid(sliceStart, sliceEnd - sliceStart); + + this->cb(scId, QString("data:%1;base64,").arg(contentType) + content.toBase64()); +} + +bool File::rmDir(const QDir &dir) { + if (dir == _persistentDir || dir == QDir::temp()) {//can't remove root dir + return false; + } + bool result = true; + if (dir.exists()) { + // Iterate over entries and remove them + Q_FOREACH(const QFileInfo &fileInfo, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) { + if (fileInfo.isDir()) { + result = rmDir(fileInfo.absoluteFilePath()); + } + else { + result = QFile::remove(fileInfo.absoluteFilePath()); + } + + if (!result) { + return result; + } + } + + // Finally remove the current dir + return dir.rmdir(dir.absolutePath()); + } + return result; +} + +bool File::copyFile(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) { + QPair destDir = resolveURI(ecId, destinationUri); + QPair sourceFile = resolveURI(ecId, sourceUri); + + if (!destDir.first || !sourceFile.first) + return false; + + if (!checkFileName(newName)) { + this->callback(ecId, FileError::kEncodingErr); + return false; + } + + if (destDir.second.isFile()) { + this->callback(ecId, FileError::kInvalidModificationErr); + return false; + } + + if (!destDir.second.isDir()) { + this->callback(ecId, FileError::kNotFoundErr); + return false; + } + + QFileInfo &fileInfo = sourceFile.second; + QString fileName((newName.isEmpty()) ? fileInfo.fileName() : newName); + QString destinationFile(QDir(destDir.second.absoluteFilePath()).filePath(fileName)); + if (QFile::copy(fileInfo.absoluteFilePath(), destinationFile)){ + this->cb(scId, file2map(QFileInfo(destinationFile))); + return true; + } + this->callback(ecId, FileError::kInvalidModificationErr); + return false; +} + +void File::copyDir(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) { + QPair destDir = resolveURI(ecId, destinationUri); + QPair sourceDir = resolveURI(ecId, sourceUri); + + if (!destDir.first || !sourceDir.first) + return; + if (!checkFileName(newName)) { + this->callback(ecId, FileError::kEncodingErr); + return; + } + + QString targetName = ((newName.isEmpty()) ? sourceDir.second.fileName() : newName); + QString target(QDir(destDir.second.absoluteFilePath()).filePath(targetName)); + + if (QFileInfo(target).isFile()){ + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + // check: copy directory into itself + if (QDir(sourceDir.second.absoluteFilePath()).relativeFilePath(target)[0] != '.'){ + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + if (!QDir(target).exists()){ + QDir(destDir.second.absoluteFilePath()).mkdir(target);; + } else{ + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + if (copyFolder(sourceDir.second.absoluteFilePath(), target)){ + this->cb(scId, dir2map(QDir(target))); + return; + } + this->callback(ecId, FileError::kInvalidModificationErr); + return; +} + +void File::copyTo(int scId, int ecId, const QString& source, const QString& destinationDir, const QString& newName) { + QPair f1 = resolveURI(ecId, source); + + if (!f1.first) + return; + + if (f1.second.isDir()) + copyDir(scId, ecId, source, destinationDir, newName); + else + copyFile(scId, ecId, source, destinationDir, newName); +} + +void File::moveFile(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName) { + QPair sourceFile = resolveURI(ecId, sourceUri); + QPair destDir = resolveURI(ecId, destinationUri); + + if (!destDir.first || !sourceFile.first) + return; + if (!checkFileName(newName)) { + this->callback(ecId, FileError::kEncodingErr); + return; + } + + QString fileName = ((newName.isEmpty()) ? sourceFile.second.fileName() : newName); + QString target = QDir(destDir.second.absoluteFilePath()).filePath(fileName); + + if (sourceFile.second == QFileInfo(target)) { + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + if (!destDir.second.exists()) { + this->callback(ecId, FileError::kNotFoundErr); + return; + } + if (!destDir.second.isDir()){ + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + if (QFileInfo(target).exists()) { + if (!QFile::remove(target)) { + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + } + + QFile::rename(sourceFile.second.absoluteFilePath(), target); + this->cb(scId, file2map(QFileInfo(target))); +} + +void File::moveDir(int scId, int ecId,const QString& sourceUri, const QString& destinationUri, const QString& newName){ + QPair sourceDir = resolveURI(ecId, sourceUri); + QPair destDir = resolveURI(ecId, destinationUri); + + if (!destDir.first || !sourceDir.first) + return; + if (!checkFileName(newName)) { + this->callback(ecId, FileError::kEncodingErr); + return; + } + + QString fileName = ((newName.isEmpty()) ? sourceDir.second.fileName() : newName); + QString target = QDir(destDir.second.absoluteFilePath()).filePath(fileName); + + if (!destDir.second.exists()){ + this->callback(ecId, FileError::kNotFoundErr); + return; + } + + if (destDir.second.isFile()){ + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + // check: copy directory into itself + if (QDir(sourceDir.second.absoluteFilePath()).relativeFilePath(target)[0] != '.'){ + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + if (QFileInfo(target).exists() && !QDir(destDir.second.absoluteFilePath()).rmdir(fileName)) { + this->callback(ecId, FileError::kInvalidModificationErr); + return; + } + + if (copyFolder(sourceDir.second.absoluteFilePath(), target)) { + rmDir(sourceDir.second.absoluteFilePath()); + this->cb(scId, file2map(QFileInfo(target))); + } else { + this->callback(ecId, FileError::kNoModificationAllowedErr); + } +} + +void File::moveTo(int scId, int ecId, const QString& source, const QString& destinationDir, const QString& newName) { + QPair f1 = resolveURI(ecId, source); + + if (!f1.first) + return; + + if (f1.second.isDir()) + moveDir(scId, ecId, source, destinationDir, newName); + else + moveFile(scId, ecId, source, destinationDir, newName); +} + +bool File::copyFolder(const QString& sourceFolder, const QString& destFolder) { + QDir sourceDir(sourceFolder); + if (!sourceDir.exists()) + return false; + QDir destDir(destFolder); + if (!destDir.exists()){ + destDir.mkdir(destFolder); + } + QStringList files = sourceDir.entryList(QDir::Files); + for (int i = 0; i< files.count(); i++) + { + QString srcName = sourceFolder + "/" + files[i]; + QString destName = destFolder + "/" + files[i]; + QFile::copy(srcName, destName); + } + files.clear(); + files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); + for (int i = 0; i< files.count(); i++) + { + QString srcName = sourceFolder + "/" + files[i]; + QString destName = destFolder + "/" + files[i]; + copyFolder(srcName, destName); + } + return true; +} diff --git a/mobile/plugins/cordova-plugin-file/src/ubuntu/file.h b/mobile/plugins/cordova-plugin-file/src/ubuntu/file.h new file mode 100644 index 0000000..de27762 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/ubuntu/file.h @@ -0,0 +1,81 @@ +/* + * Licensed 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. + */ + +#ifndef FILEAPI_H_SDASDASDAS +#define FILEAPI_H_SDASDASDAS + +#include +#include + +#include +#include + +class File: public CPlugin { + Q_OBJECT +public: + explicit File(Cordova *cordova); + + virtual const QString fullName() override { + return File::fullID(); + } + + virtual const QString shortName() override { + return "File"; + } + + static const QString fullID() { + return "File"; + } + QPair resolveURI(const QString &uri); + QPair resolveURI(int ecId, const QString &uri); + QVariantMap file2map(const QFileInfo &dir); + +public slots: + void requestFileSystem(int scId, int ecId, unsigned short type, unsigned long long size); + void resolveLocalFileSystemURI(int scId, int ecId, const QString&); + void getDirectory(int scId, int ecId, const QString&, const QString&, const QVariantMap&); + void getFile(int scId, int ecId, const QString &parentPath, const QString &rpath, const QVariantMap &options); + void readEntries(int scId, int ecId, const QString &uri); + void getParent(int scId, int ecId, const QString &uri); + void copyTo(int scId, int ecId, const QString& source, const QString& destinationDir, const QString& newName); + void moveTo(int scId, int ecId, const QString& source, const QString& destinationDir, const QString& newName); + void getFileMetadata(int scId, int ecId, const QString &); + void getMetadata(int scId, int ecId, const QString &); + void remove(int scId, int ecId, const QString &); + void removeRecursively(int scId, int ecId, const QString&); + void write(int scId, int ecId, const QString&, const QString&, unsigned long long position, bool binary); + void readAsText(int scId, int ecId, const QString&, const QString &encoding, int sliceStart, int sliceEnd); + void readAsDataURL(int scId, int ecId, const QString&, int sliceStart, int sliceEnd); + void readAsArrayBuffer(int scId, int ecId, const QString&, int sliceStart, int sliceEnd); + void readAsBinaryString(int scId, int ecId, const QString&, int sliceStart, int sliceEnd); + void truncate(int scId, int ecId, const QString&, unsigned long long size); + + void _getLocalFilesystemPath(int scId, int ecId, const QString&); +private: + void moveFile(int scId, int ecId,const QString&, const QString&, const QString&); + void moveDir(int scId, int ecId,const QString&, const QString&, const QString&); + bool copyFile(int scId, int ecId, const QString&, const QString&, const QString&); + void copyDir(int scId, int ecId, const QString&, const QString&, const QString&); + bool rmDir(const QDir &dir); + bool copyFolder(const QString&, const QString&); + + QPair GetRelativePath(const QFileInfo &fileInfo); + QVariantMap dir2map(const QDir &dir); + + QMimeDatabase _db; + const QDir _persistentDir; + QNetworkAccessManager _manager; +}; + +#endif diff --git a/mobile/plugins/cordova-plugin-file/src/windows/FileProxy.js b/mobile/plugins/cordova-plugin-file/src/windows/FileProxy.js new file mode 100644 index 0000000..fa56a53 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/windows/FileProxy.js @@ -0,0 +1,1209 @@ +/* + * + * 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. + * +*/ + +/* global Windows, WinJS, MSApp */ + +var File = require('./File'), + FileError = require('./FileError'), + Flags = require('./Flags'), + FileSystem = require('./FileSystem'), + LocalFileSystem = require('./LocalFileSystem'), + utils = require('cordova/utils'); + +function Entry(isFile, isDirectory, name, fullPath, filesystemName, nativeURL) { + this.isFile = !!isFile; + this.isDirectory = !!isDirectory; + this.name = name || ''; + this.fullPath = fullPath || ''; + this.filesystemName = filesystemName || null; + this.nativeURL = nativeURL || null; +} + +var FileEntry = function(name, fullPath, filesystemName, nativeURL) { + FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, filesystemName, nativeURL]); +}; + +utils.extend(FileEntry, Entry); + +var DirectoryEntry = function(name, fullPath, filesystemName, nativeURL) { + DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, filesystemName, nativeURL); +}; + +utils.extend(DirectoryEntry, Entry); + + +var getFolderFromPathAsync = Windows.Storage.StorageFolder.getFolderFromPathAsync; +var getFileFromPathAsync = Windows.Storage.StorageFile.getFileFromPathAsync; + +function writeBytesAsync(storageFile, data, position) { + return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite) + .then(function (output) { + output.seek(position); + var dataWriter = new Windows.Storage.Streams.DataWriter(output); + dataWriter.writeBytes(data); + return dataWriter.storeAsync().then(function (size) { + output.size = position+size; + return dataWriter.flushAsync().then(function() { + output.close(); + return size; + }); + }); + }); +} + +function writeTextAsync(storageFile, data, position) { + return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite) + .then(function (output) { + output.seek(position); + var dataWriter = new Windows.Storage.Streams.DataWriter(output); + dataWriter.writeString(data); + return dataWriter.storeAsync().then(function (size) { + output.size = position+size; + return dataWriter.flushAsync().then(function() { + output.close(); + return size; + }); + }); + }); +} + +function writeBlobAsync(storageFile, data, position) { + return storageFile.openAsync(Windows.Storage.FileAccessMode.readWrite) + .then(function (output) { + output.seek(position); + var dataSize = data.size; + var input = (data.detachStream || data.msDetachStream).call(data); + + // Copy the stream from the blob to the File stream + return Windows.Storage.Streams.RandomAccessStream.copyAsync(input, output) + .then(function () { + output.size = position+dataSize; + return output.flushAsync().then(function () { + input.close(); + output.close(); + + return dataSize; + }); + }); + }); +} + +function writeArrayBufferAsync(storageFile, data, position) { + return writeBlobAsync(storageFile, new Blob([data]), position); +} + +function cordovaPathToNative(path) { + // turn / into \\ + var cleanPath = path.replace(/\//g, '\\'); + // turn \\ into \ + cleanPath = cleanPath.replace(/\\+/g, '\\'); + return cleanPath; +} + +function nativePathToCordova(path) { + var cleanPath = path.replace(/\\/g, '/'); + return cleanPath; +} + +var driveRE = new RegExp("^[/]*([A-Z]:)"); +var invalidNameRE = /[\\?*|"<>:]/; +function validName(name) { + return !invalidNameRE.test(name.replace(driveRE,'')); +} + +function sanitize(path) { + var slashesRE = new RegExp('/{2,}','g'); + var components = path.replace(slashesRE, '/').split(/\/+/); + // Remove double dots, use old school array iteration instead of RegExp + // since it is impossible to debug them + for (var index = 0; index < components.length; ++index) { + if (components[index] === "..") { + components.splice(index, 1); + if (index > 0) { + // if we're not in the start of array then remove preceeding path component, + // In case if relative path points above the root directory, just ignore double dots + // See file.spec.111 should not traverse above above the root directory for test case + components.splice(index-1, 1); + --index; + } + } + } + return components.join('/'); +} + +var WinFS = function(name, root) { + this.winpath = root.winpath; + if (this.winpath && !/\/$/.test(this.winpath)) { + this.winpath += "/"; + } + this.makeNativeURL = function (path) { + //CB-11848: This RE supposed to match all leading slashes in sanitized path. + //Removing leading slash to avoid duplicating because this.root.nativeURL already has trailing slash + var regLeadingSlashes = /^\/*/; + var sanitizedPath = sanitize(path.replace(':', '%3A')).replace(regLeadingSlashes, ''); + return FileSystem.encodeURIPath(this.root.nativeURL + sanitizedPath); + }; + root.fullPath = '/'; + if (!root.nativeURL) + root.nativeURL = 'file://'+sanitize(this.winpath + root.fullPath).replace(':','%3A'); + WinFS.__super__.constructor.call(this, name, root); +}; + +utils.extend(WinFS, FileSystem); + +WinFS.prototype.__format__ = function(fullPath) { + var path = sanitize('/'+this.name+(fullPath[0]==='/'?'':'/')+FileSystem.encodeURIPath(fullPath)); + return 'cdvfile://localhost' + path; +}; + +var windowsPaths = { + dataDirectory: "ms-appdata:///local/", + cacheDirectory: "ms-appdata:///temp/", + tempDirectory: "ms-appdata:///temp/", + syncedDataDirectory: "ms-appdata:///roaming/", + applicationDirectory: "ms-appx:///", + applicationStorageDirectory: "ms-appx:///" +}; + +var AllFileSystems; + +function getAllFS() { + if (!AllFileSystems) { + AllFileSystems = { + 'persistent': + Object.freeze(new WinFS('persistent', { + name: 'persistent', + nativeURL: 'ms-appdata:///local', + winpath: nativePathToCordova(Windows.Storage.ApplicationData.current.localFolder.path) + })), + 'temporary': + Object.freeze(new WinFS('temporary', { + name: 'temporary', + nativeURL: 'ms-appdata:///temp', + winpath: nativePathToCordova(Windows.Storage.ApplicationData.current.temporaryFolder.path) + })), + 'application': + Object.freeze(new WinFS('application', { + name: 'application', + nativeURL: 'ms-appx:///', + winpath: nativePathToCordova(Windows.ApplicationModel.Package.current.installedLocation.path) + })), + 'root': + Object.freeze(new WinFS('root', { + name: 'root', + //nativeURL: 'file:///' + winpath: '' + })) + }; + } + return AllFileSystems; +} + +function getFS(name) { + return getAllFS()[name]; +} + +FileSystem.prototype.__format__ = function(fullPath) { + return getFS(this.name).__format__(fullPath); +}; + +require('./fileSystems').getFs = function(name, callback) { + setTimeout(function(){callback(getFS(name));}); +}; + +function getFilesystemFromPath(path) { + var res; + var allfs = getAllFS(); + Object.keys(allfs).some(function(fsn) { + var fs = allfs[fsn]; + if (path.indexOf(fs.winpath) === 0) + res = fs; + return res; + }); + return res; +} + +var msapplhRE = new RegExp('^ms-appdata://localhost/'); +function pathFromURL(url) { + url=url.replace(msapplhRE,'ms-appdata:///'); + var path = decodeURIComponent(url); + // support for file name with parameters + if (/\?/g.test(path)) { + path = String(path).split("?")[0]; + } + if (path.indexOf("file:/")===0) { + if (path.indexOf("file://") !== 0) { + url = "file:///" + url.substr(6); + } + } + + ['file://','ms-appdata:///','ms-appx://','cdvfile://localhost/'].every(function(p) { + if (path.indexOf(p)!==0) + return true; + var thirdSlash = path.indexOf("/", p.length); + if (thirdSlash < 0) { + path = ""; + } else { + path = sanitize(path.substr(thirdSlash)); + } + }); + + return path.replace(driveRE,'$1'); +} + +function getFilesystemFromURL(url) { + url=url.replace(msapplhRE,'ms-appdata:///'); + var res; + if (url.indexOf("file:/")===0) + res = getFilesystemFromPath(pathFromURL(url)); + else { + var allfs = getAllFS(); + Object.keys(allfs).every(function(fsn) { + var fs = allfs[fsn]; + if (url.indexOf(fs.root.nativeURL) === 0 || + url.indexOf('cdvfile://localhost/'+fs.name+'/') === 0) + { + res = fs; + return false; + } + return true; + }); + } + return res; +} + +function getFsPathForWinPath(fs, wpath) { + var path = nativePathToCordova(wpath); + if (path.indexOf(fs.winpath) !== 0) + return null; + return path.replace(fs.winpath,'/'); +} + +var WinError = { + invalidArgument: -2147024809, + fileNotFound: -2147024894, + accessDenied: -2147024891 +}; + +function openPath(path, ops) { + ops=ops?ops:{}; + return new WinJS.Promise(function (complete,failed) { + getFileFromPathAsync(path).done( + function(file) { + complete({file:file}); + }, + function(err) { + if (err.number != WinError.fileNotFound && err.number != WinError.invalidArgument) + failed(FileError.NOT_READABLE_ERR); + getFolderFromPathAsync(path) + .done( + function(dir) { + if (!ops.getContent) + complete({folder:dir}); + else + WinJS.Promise.join({ + files:dir.getFilesAsync(), + folders:dir.getFoldersAsync() + }).done( + function(a) { + complete({ + folder:dir, + files:a.files, + folders:a.folders + }); + }, + function(err) { + failed(FileError.NOT_READABLE_ERR); + } + ); + }, + function(err) { + if (err.number == WinError.fileNotFound || err.number == WinError.invalidArgument) + complete({}); + else + failed(FileError.NOT_READABLE_ERR); + } + ); + } + ); + }); +} + +function copyFolder(src,dst,name) { + name = name?name:src.name; + return new WinJS.Promise(function (complete,failed) { + WinJS.Promise.join({ + fld:dst.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists), + files:src.getFilesAsync(), + folders:src.getFoldersAsync() + }).done( + function(the) { + if (!(the.files.length || the.folders.length)) { + complete(); + return; + } + var todo = the.files.length; + var copyfolders = function() { + if (!(todo--)) { + complete(); + return; + } + copyFolder(the.folders[todo],dst) + .done(function() { copyfolders(); }, failed); + }; + var copyfiles = function() { + if (!(todo--)) { + todo = the.folders.length; + copyfolders(); + return; + } + the.files[todo].copyAsync(the.fld) + .done(function() { copyfiles(); }, failed); + }; + copyfiles(); + }, + failed + ); + }); +} + +function moveFolder(src,dst,name) { + name = name?name:src.name; + return new WinJS.Promise(function (complete,failed) { + WinJS.Promise.join({ + fld: dst.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists), + files: src.getFilesAsync(), + folders: src.getFoldersAsync() + }).done( + function(the) { + if (!(the.files.length || the.folders.length)) { + complete(); + return; + } + var todo = the.files.length; + var movefolders = function() { + if (!(todo--)) { + src.deleteAsync().done(complete,failed); + return; + } + moveFolder(the.folders[todo], the.fld) + .done(movefolders,failed); + }; + var movefiles = function() { + if (!(todo--)) { + todo = the.folders.length; + movefolders(); + return; + } + the.files[todo].moveAsync(the.fld) + .done(function() { movefiles(); }, failed); + }; + movefiles(); + }, + failed + ); + }); +} + +function transport(success, fail, args, ops) { // ["fullPath","parent", "newName"] + var src = args[0]; + var parent = args[1]; + var name = args[2]; + + var srcFS = getFilesystemFromURL(src); + var dstFS = getFilesystemFromURL(parent); + var srcPath = pathFromURL(src); + var dstPath = pathFromURL(parent); + if (!(srcFS && dstFS && validName(name))){ + fail(FileError.ENCODING_ERR); + return; + } + + var srcWinPath = cordovaPathToNative(sanitize(srcFS.winpath + srcPath)); + var dstWinPath = cordovaPathToNative(sanitize(dstFS.winpath + dstPath)); + var tgtFsPath = sanitize(dstPath+'/'+name); + var tgtWinPath = cordovaPathToNative(sanitize(dstFS.winpath + dstPath+'/'+name)); + if (srcWinPath == dstWinPath || srcWinPath == tgtWinPath) { + fail(FileError.INVALID_MODIFICATION_ERR); + return; + } + + + WinJS.Promise.join({ + src:openPath(srcWinPath), + dst:openPath(dstWinPath), + tgt:openPath(tgtWinPath,{getContent:true}) + }) + .done( + function (the) { + if ((!the.dst.folder) || !(the.src.folder || the.src.file)) { + fail(FileError.NOT_FOUND_ERR); + return; + } + if ((the.src.folder && the.tgt.file) || + (the.src.file && the.tgt.folder) || + (the.tgt.folder && (the.tgt.files.length || the.tgt.folders.length))) { + fail(FileError.INVALID_MODIFICATION_ERR); + return; + } + if (the.src.file) + ops.fileOp(the.src.file,the.dst.folder, name, Windows.Storage.NameCollisionOption.replaceExisting) + .done( + function (storageFile) { + success(new FileEntry( + name, + tgtFsPath, + dstFS.name, + dstFS.makeNativeURL(tgtFsPath) + )); + }, + function (err) { + fail(FileError.INVALID_MODIFICATION_ERR); + } + ); + else + ops.folderOp(the.src.folder, the.dst.folder, name).done( + function () { + success(new DirectoryEntry( + name, + tgtFsPath, + dstFS.name, + dstFS.makeNativeURL(tgtFsPath) + )); + }, + function() { + fail(FileError.INVALID_MODIFICATION_ERR); + } + ); + }, + function(err) { + fail(FileError.INVALID_MODIFICATION_ERR); + } + ); +} + +module.exports = { + requestAllFileSystems: function() { + return getAllFS(); + }, + requestAllPaths: function(success){ + success(windowsPaths); + }, + getFileMetadata: function (success, fail, args) { + module.exports.getMetadata(success, fail, args); + }, + + getMetadata: function (success, fail, args) { + var fs = getFilesystemFromURL(args[0]); + var path = pathFromURL(args[0]); + if (!fs || !validName(path)){ + fail(FileError.ENCODING_ERR); + return; + } + var fullPath = cordovaPathToNative(fs.winpath + path); + + var getMetadataForFile = function (storageFile) { + storageFile.getBasicPropertiesAsync().then( + function (basicProperties) { + success(new File(storageFile.name, storageFile.path, storageFile.fileType, basicProperties.dateModified, basicProperties.size)); + }, function () { + fail(FileError.NOT_READABLE_ERR); + } + ); + }; + + var getMetadataForFolder = function (storageFolder) { + storageFolder.getBasicPropertiesAsync().then( + function (basicProperties) { + var metadata = { + size: basicProperties.size, + lastModifiedDate: basicProperties.dateModified + }; + success(metadata); + }, + function () { + fail(FileError.NOT_READABLE_ERR); + } + ); + }; + + getFileFromPathAsync(fullPath).then(getMetadataForFile, + function () { + getFolderFromPathAsync(fullPath).then(getMetadataForFolder, + function () { + fail(FileError.NOT_FOUND_ERR); + } + ); + } + ); + }, + + getParent: function (win, fail, args) { // ["fullPath"] + var fs = getFilesystemFromURL(args[0]); + var path = pathFromURL(args[0]); + if (!fs || !validName(path)){ + fail(FileError.ENCODING_ERR); + return; + } + if (!path || (new RegExp('/[^/]*/?$')).test(path)) { + win(new DirectoryEntry(fs.root.name, fs.root.fullPath, fs.name, fs.makeNativeURL(fs.root.fullPath))); + return; + } + + var parpath = path.replace(new RegExp('/[^/]+/?$','g'),''); + var parname = path.substr(parpath.length); + var fullPath = cordovaPathToNative(fs.winpath + parpath); + + var result = new DirectoryEntry(parname, parpath, fs.name, fs.makeNativeURL(parpath)); + getFolderFromPathAsync(fullPath).done( + function () { win(result); }, + function () { fail(FileError.INVALID_STATE_ERR); } + ); + }, + + readAsText: function (win, fail, args) { + + var url = args[0], + enc = args[1], + startPos = args[2], + endPos = args[3]; + + var fs = getFilesystemFromURL(url); + var path = pathFromURL(url); + if (!fs){ + fail(FileError.ENCODING_ERR); + return; + } + var wpath = cordovaPathToNative(sanitize(fs.winpath + path)); + + var encoding = Windows.Storage.Streams.UnicodeEncoding.utf8; + if (enc == 'Utf16LE' || enc == 'utf16LE') { + encoding = Windows.Storage.Streams.UnicodeEncoding.utf16LE; + } else if (enc == 'Utf16BE' || enc == 'utf16BE') { + encoding = Windows.Storage.Streams.UnicodeEncoding.utf16BE; + } + + getFileFromPathAsync(wpath).then(function(file) { + return file.openReadAsync(); + }).then(function (stream) { + startPos = (startPos < 0) ? Math.max(stream.size + startPos, 0) : Math.min(stream.size, startPos); + endPos = (endPos < 0) ? Math.max(endPos + stream.size, 0) : Math.min(stream.size, endPos); + stream.seek(startPos); + + var readSize = endPos - startPos, + buffer = new Windows.Storage.Streams.Buffer(readSize); + + return stream.readAsync(buffer, readSize, Windows.Storage.Streams.InputStreamOptions.none); + }).done(function(buffer) { + try { + win(Windows.Security.Cryptography.CryptographicBuffer.convertBinaryToString(encoding, buffer)); + } + catch (e) { + fail(FileError.ENCODING_ERR); + } + },function() { + fail(FileError.NOT_FOUND_ERR); + }); + }, + + readAsBinaryString:function(win,fail,args) { + var url = args[0], + startPos = args[1], + endPos = args[2]; + + var fs = getFilesystemFromURL(url); + var path = pathFromURL(url); + if (!fs){ + fail(FileError.ENCODING_ERR); + return; + } + var wpath = cordovaPathToNative(sanitize(fs.winpath + path)); + + getFileFromPathAsync(wpath).then( + function (storageFile) { + Windows.Storage.FileIO.readBufferAsync(storageFile).done( + function (buffer) { + var dataReader = Windows.Storage.Streams.DataReader.fromBuffer(buffer); + // var fileContent = dataReader.readString(buffer.length); + var byteArray = new Uint8Array(buffer.length), + byteString = ""; + dataReader.readBytes(byteArray); + dataReader.close(); + for (var i = 0; i < byteArray.length; i++) { + var charByte = byteArray[i]; + // var charRepresentation = charByte <= 127 ? String.fromCharCode(charByte) : charByte.toString(16); + var charRepresentation = String.fromCharCode(charByte); + byteString += charRepresentation; + } + win(byteString.slice(startPos, endPos)); + } + ); + }, function () { + fail(FileError.NOT_FOUND_ERR); + } + ); + }, + + readAsArrayBuffer:function(win,fail,args) { + var url = args[0]; + var fs = getFilesystemFromURL(url); + var path = pathFromURL(url); + if (!fs){ + fail(FileError.ENCODING_ERR); + return; + } + var wpath = cordovaPathToNative(sanitize(fs.winpath + path)); + + getFileFromPathAsync(wpath).then( + function (storageFile) { + var blob = MSApp.createFileFromStorageFile(storageFile); + var url = URL.createObjectURL(blob, { oneTimeOnly: true }); + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = 'arraybuffer'; + xhr.onload = function () { + var resultArrayBuffer = xhr.response; + // get start and end position of bytes in buffer to be returned + var startPos = args[1] || 0, + endPos = args[2] || resultArrayBuffer.length; + // if any of them is specified, we'll slice output array + if (startPos !== 0 || endPos !== resultArrayBuffer.length) { + // slice method supported only on Windows 8.1, so we need to check if it's available + // see http://msdn.microsoft.com/en-us/library/ie/dn641192(v=vs.94).aspx + if (resultArrayBuffer.slice) { + resultArrayBuffer = resultArrayBuffer.slice(startPos, endPos); + } else { + // if slice isn't available, we'll use workaround method + var tempArray = new Uint8Array(resultArrayBuffer), + resBuffer = new ArrayBuffer(endPos - startPos), + resArray = new Uint8Array(resBuffer); + + for (var i = 0; i < resArray.length; i++) { + resArray[i] = tempArray[i + startPos]; + } + resultArrayBuffer = resBuffer; + } + } + win(resultArrayBuffer); + }; + xhr.send(); + }, function () { + fail(FileError.NOT_FOUND_ERR); + } + ); + }, + + readAsDataURL: function (win, fail, args) { + var url = args[0]; + var fs = getFilesystemFromURL(url); + var path = pathFromURL(url); + if (!fs){ + fail(FileError.ENCODING_ERR); + return; + } + var wpath = cordovaPathToNative(sanitize(fs.winpath + path)); + + getFileFromPathAsync(wpath).then( + function (storageFile) { + Windows.Storage.FileIO.readBufferAsync(storageFile).done( + function (buffer) { + var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer); + //the method encodeToBase64String will add "77u/" as a prefix, so we should remove it + if(String(strBase64).substr(0,4) == "77u/") { + strBase64 = strBase64.substr(4); + } + var mediaType = storageFile.contentType; + var result = "data:" + mediaType + ";base64," + strBase64; + win(result); + } + ); + }, function () { + fail(FileError.NOT_FOUND_ERR); + } + ); + }, + + getDirectory: function (win, fail, args) { + var dirurl = args[0]; + var path = args[1]; + var options = args[2]; + + var fs = getFilesystemFromURL(dirurl); + var dirpath = pathFromURL(dirurl); + if (!fs || !validName(path)){ + fail(FileError.ENCODING_ERR); + return; + } + var fspath = sanitize(dirpath +'/'+ path); + var completePath = sanitize(fs.winpath + fspath); + + var name = completePath.substring(completePath.lastIndexOf('/')+1); + + var wpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/'))); + + var flag = ""; + if (options) { + flag = new Flags(options.create, options.exclusive); + } else { + flag = new Flags(false, false); + } + + getFolderFromPathAsync(wpath).done( + function (storageFolder) { + if (flag.create === true && flag.exclusive === true) { + storageFolder.createFolderAsync(name, Windows.Storage.CreationCollisionOption.failIfExists).done( + function (storageFolder) { + win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath))); + }, function (err) { + fail(FileError.PATH_EXISTS_ERR); + } + ); + } else if (flag.create === true && flag.exclusive === false) { + storageFolder.createFolderAsync(name, Windows.Storage.CreationCollisionOption.openIfExists).done( + function (storageFolder) { + win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath))); + }, function () { + fail(FileError.INVALID_MODIFICATION_ERR); + } + ); + } else if (flag.create === false) { + storageFolder.getFolderAsync(name).done( + function (storageFolder) { + win(new DirectoryEntry(storageFolder.name, fspath, fs.name, fs.makeNativeURL(fspath))); + }, + function () { + // check if path actually points to a file + storageFolder.getFileAsync(name).done( + function () { + fail(FileError.TYPE_MISMATCH_ERR); + }, function() { + fail(FileError.NOT_FOUND_ERR); + } + ); + } + ); + } + }, function () { + fail(FileError.NOT_FOUND_ERR); + } + ); + }, + + remove: function (win, fail, args) { + var fs = getFilesystemFromURL(args[0]); + var path = pathFromURL(args[0]); + if (!fs || !validName(path)){ + fail(FileError.ENCODING_ERR); + return; + } + + // FileSystem root can't be removed! + if (!path || path=='/'){ + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + return; + } + var fullPath = cordovaPathToNative(fs.winpath + path); + + getFileFromPathAsync(fullPath).then( + function (storageFile) { + storageFile.deleteAsync().done(win, function () { + fail(FileError.INVALID_MODIFICATION_ERR); + }); + }, + function () { + getFolderFromPathAsync(fullPath).done( + function (sFolder) { + sFolder.getFilesAsync() + // check for files + .then(function(fileList) { + if (fileList) { + if (fileList.length === 0) { + return sFolder.getFoldersAsync(); + } else { + fail(FileError.INVALID_MODIFICATION_ERR); + } + } + }) + // check for folders + .done(function (folderList) { + if (folderList) { + if (folderList.length === 0) { + sFolder.deleteAsync().done( + win, + function () { + fail(FileError.INVALID_MODIFICATION_ERR); + } + ); + } else { + fail(FileError.INVALID_MODIFICATION_ERR); + } + } + }); + }, + function () { + fail(FileError.NOT_FOUND_ERR); + } + ); + } + ); + }, + + removeRecursively: function (successCallback, fail, args) { + + var fs = getFilesystemFromURL(args[0]); + var path = pathFromURL(args[0]); + if (!fs || !validName(path)){ + fail(FileError.ENCODING_ERR); + return; + } + + // FileSystem root can't be removed! + if (!path || path=='/'){ + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + return; + } + var fullPath = cordovaPathToNative(fs.winpath + path); + + getFolderFromPathAsync(fullPath).done(function (storageFolder) { + storageFolder.deleteAsync().done(function (res) { + successCallback(res); + }, function (err) { + fail(err); + }); + + }, function () { + fail(FileError.FILE_NOT_FOUND_ERR); + }); + }, + + getFile: function (win, fail, args) { + + var dirurl = args[0]; + var path = args[1]; + var options = args[2]; + + var fs = getFilesystemFromURL(dirurl); + var dirpath = pathFromURL(dirurl); + if (!fs || !validName(path)){ + fail(FileError.ENCODING_ERR); + return; + } + var fspath = sanitize(dirpath +'/'+ path); + var completePath = sanitize(fs.winpath + fspath); + + var fileName = completePath.substring(completePath.lastIndexOf('/')+1); + + var wpath = cordovaPathToNative(completePath.substring(0, completePath.lastIndexOf('/'))); + + var flag = ""; + if (options !== null) { + flag = new Flags(options.create, options.exclusive); + } else { + flag = new Flags(false, false); + } + + getFolderFromPathAsync(wpath).done( + function (storageFolder) { + if (flag.create === true && flag.exclusive === true) { + storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.failIfExists).done( + function (storageFile) { + win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath))); + }, function () { + fail(FileError.PATH_EXISTS_ERR); + } + ); + } else if (flag.create === true && flag.exclusive === false) { + storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.openIfExists).done( + function (storageFile) { + win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath))); + }, function () { + fail(FileError.INVALID_MODIFICATION_ERR); + } + ); + } else if (flag.create === false) { + storageFolder.getFileAsync(fileName).done( + function (storageFile) { + win(new FileEntry(storageFile.name, fspath, fs.name, fs.makeNativeURL(fspath))); + }, function () { + // check if path actually points to a folder + storageFolder.getFolderAsync(fileName).done( + function () { + fail(FileError.TYPE_MISMATCH_ERR); + }, function () { + fail(FileError.NOT_FOUND_ERR); + }); + } + ); + } + }, function (err) { + fail( + err.number == WinError.accessDenied? + FileError.SECURITY_ERR: + FileError.NOT_FOUND_ERR + ); + } + ); + }, + + readEntries: function (win, fail, args) { // ["fullPath"] + var fs = getFilesystemFromURL(args[0]); + var path = pathFromURL(args[0]); + if (!fs || !validName(path)){ + fail(FileError.ENCODING_ERR); + return; + } + var fullPath = cordovaPathToNative(fs.winpath + path); + + var result = []; + + getFolderFromPathAsync(fullPath).done(function (storageFolder) { + var promiseArr = []; + var index = 0; + promiseArr[index++] = storageFolder.getFilesAsync().then(function (fileList) { + if (fileList !== null) { + for (var i = 0; i < fileList.length; i++) { + var fspath = getFsPathForWinPath(fs, fileList[i].path); + if (!fspath) { + fail(FileError.NOT_FOUND_ERR); + return; + } + result.push(new FileEntry(fileList[i].name, fspath, fs.name, fs.makeNativeURL(fspath))); + } + } + }); + promiseArr[index++] = storageFolder.getFoldersAsync().then(function (folderList) { + if (folderList !== null) { + for (var j = 0; j < folderList.length; j++) { + var fspath = getFsPathForWinPath(fs, folderList[j].path); + if (!fspath) { + fail(FileError.NOT_FOUND_ERR); + return; + } + result.push(new DirectoryEntry(folderList[j].name, fspath, fs.name, fs.makeNativeURL(fspath))); + } + } + }); + WinJS.Promise.join(promiseArr).then(function () { + win(result); + }); + + }, function () { fail(FileError.NOT_FOUND_ERR); }); + }, + + write: function (win, fail, args) { + + var url = args[0], + data = args[1], + position = args[2], + isBinary = args[3]; + + var fs = getFilesystemFromURL(url); + var path = pathFromURL(url); + if (!fs){ + fail(FileError.ENCODING_ERR); + return; + } + var completePath = sanitize(fs.winpath + path); + var fileName = completePath.substring(completePath.lastIndexOf('/')+1); + var dirpath = completePath.substring(0,completePath.lastIndexOf('/')); + var wpath = cordovaPathToNative(dirpath); + + function getWriteMethodForData(data, isBinary) { + + if (data instanceof Blob) { + return writeBlobAsync; + } + + if (data instanceof ArrayBuffer) { + return writeArrayBufferAsync; + } + + if (isBinary) { + return writeBytesAsync; + } + + if (typeof data === 'string') { + return writeTextAsync; + } + + throw new Error('Unsupported data type for write method'); + } + + var writePromise = getWriteMethodForData(data, isBinary); + + getFolderFromPathAsync(wpath).done( + function (storageFolder) { + storageFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.openIfExists).done( + function (storageFile) { + writePromise(storageFile, data, position).done( + function (bytesWritten) { + var written = bytesWritten || data.length; + win(written); + }, + function () { + fail(FileError.INVALID_MODIFICATION_ERR); + } + ); + }, + function () { + fail(FileError.INVALID_MODIFICATION_ERR); + } + ); + + }, + function () { + fail(FileError.NOT_FOUND_ERR); + } + ); + }, + + truncate: function (win, fail, args) { // ["fileName","size"] + var url = args[0]; + var size = args[1]; + + var fs = getFilesystemFromURL(url); + var path = pathFromURL(url); + if (!fs){ + fail(FileError.ENCODING_ERR); + return; + } + var completePath = sanitize(fs.winpath + path); + var wpath = cordovaPathToNative(completePath); + var dirwpath = cordovaPathToNative(completePath.substring(0,completePath.lastIndexOf('/'))); + + getFileFromPathAsync(wpath).done(function(storageFile){ + //the current length of the file. + var leng = 0; + + storageFile.getBasicPropertiesAsync().then(function (basicProperties) { + leng = basicProperties.size; + if (Number(size) >= leng) { + win(this.length); + return; + } + if (Number(size) >= 0) { + Windows.Storage.FileIO.readTextAsync(storageFile, Windows.Storage.Streams.UnicodeEncoding.utf8).then(function (fileContent) { + fileContent = fileContent.substr(0, size); + var name = storageFile.name; + storageFile.deleteAsync().then(function () { + return getFolderFromPathAsync(dirwpath); + }).done(function (storageFolder) { + storageFolder.createFileAsync(name).then(function (newStorageFile) { + Windows.Storage.FileIO.writeTextAsync(newStorageFile, fileContent).done(function () { + win(String(fileContent).length); + }, function () { + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + }); + }, function() { + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + }); + }); + }, function () { fail(FileError.NOT_FOUND_ERR); }); + } + }); + }, function () { fail(FileError.NOT_FOUND_ERR); }); + }, + + copyTo: function (success, fail, args) { // ["fullPath","parent", "newName"] + transport(success, fail, args, + { + fileOp:function(file,folder,name,coll) { + return file.copyAsync(folder,name,coll); + }, + folderOp:function(src,dst,name) { + return copyFolder(src,dst,name); + }} + ); + }, + + moveTo: function (success, fail, args) { + transport(success, fail, args, + { + fileOp:function(file,folder,name,coll) { + return file.moveAsync(folder,name,coll); + }, + folderOp:function(src,dst,name) { + return moveFolder(src,dst,name); + }} + ); + }, + tempFileSystem:null, + + persistentFileSystem:null, + + requestFileSystem: function (win, fail, args) { + + var type = args[0]; + var size = args[1]; + var MAX_SIZE = 10000000000; + if (size > MAX_SIZE) { + fail(FileError.QUOTA_EXCEEDED_ERR); + return; + } + + var fs; + switch (type) { + case LocalFileSystem.TEMPORARY: + fs = getFS('temporary'); + break; + case LocalFileSystem.PERSISTENT: + fs = getFS('persistent'); + break; + } + if (fs) + win(fs); + else + fail(FileError.NOT_FOUND_ERR); + }, + + resolveLocalFileSystemURI: function (success, fail, args) { + + var uri = args[0]; + + var path = pathFromURL(uri); + var fs = getFilesystemFromURL(uri); + if (!fs || !validName(path)) { + fail(FileError.ENCODING_ERR); + return; + } + if (path.indexOf(fs.winpath) === 0) + path=path.substr(fs.winpath.length); + var abspath = cordovaPathToNative(fs.winpath+path); + + getFileFromPathAsync(abspath).done( + function (storageFile) { + success(new FileEntry(storageFile.name, path, fs.name, fs.makeNativeURL(path))); + }, function () { + getFolderFromPathAsync(abspath).done( + function (storageFolder) { + success(new DirectoryEntry(storageFolder.name, path, fs.name,fs.makeNativeURL(path))); + }, function () { + fail(FileError.NOT_FOUND_ERR); + } + ); + } + ); + } + + +}; + +require("cordova/exec/proxy").add("File",module.exports); diff --git a/mobile/plugins/cordova-plugin-file/src/wp/File.cs b/mobile/plugins/cordova-plugin-file/src/wp/File.cs new file mode 100644 index 0000000..941c9c8 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/src/wp/File.cs @@ -0,0 +1,1800 @@ +/* + Licensed 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. +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.IsolatedStorage; +using System.Runtime.Serialization; +using System.Security; +using System.Text; +using System.Windows; +using System.Windows.Resources; +using WPCordovaClassLib.Cordova.JSON; + +namespace WPCordovaClassLib.Cordova.Commands +{ + /// + /// Provides access to isolated storage + /// + public class File : BaseCommand + { + // Error codes + public const int NOT_FOUND_ERR = 1; + public const int SECURITY_ERR = 2; + public const int ABORT_ERR = 3; + public const int NOT_READABLE_ERR = 4; + public const int ENCODING_ERR = 5; + public const int NO_MODIFICATION_ALLOWED_ERR = 6; + public const int INVALID_STATE_ERR = 7; + public const int SYNTAX_ERR = 8; + public const int INVALID_MODIFICATION_ERR = 9; + public const int QUOTA_EXCEEDED_ERR = 10; + public const int TYPE_MISMATCH_ERR = 11; + public const int PATH_EXISTS_ERR = 12; + + // File system options + public const int TEMPORARY = 0; + public const int PERSISTENT = 1; + public const int RESOURCE = 2; + public const int APPLICATION = 3; + + /// + /// Temporary directory name + /// + private readonly string TMP_DIRECTORY_NAME = "tmp"; + + /// + /// Represents error code for callback + /// + [DataContract] + public class ErrorCode + { + /// + /// Error code + /// + [DataMember(IsRequired = true, Name = "code")] + public int Code { get; set; } + + /// + /// Creates ErrorCode object + /// + public ErrorCode(int code) + { + this.Code = code; + } + } + + /// + /// Represents File action options. + /// + [DataContract] + public class FileOptions + { + /// + /// File path + /// + /// + private string _fileName; + [DataMember(Name = "fileName")] + public string FilePath + { + get + { + return this._fileName; + } + + set + { + int index = value.IndexOfAny(new char[] { '#', '?' }); + this._fileName = index > -1 ? value.Substring(0, index) : value; + } + } + + /// + /// Full entryPath + /// + [DataMember(Name = "fullPath")] + public string FullPath { get; set; } + + /// + /// Directory name + /// + [DataMember(Name = "dirName")] + public string DirectoryName { get; set; } + + /// + /// Path to create file/directory + /// + [DataMember(Name = "path")] + public string Path { get; set; } + + /// + /// The encoding to use to encode the file's content. Default is UTF8. + /// + [DataMember(Name = "encoding")] + public string Encoding { get; set; } + + /// + /// Uri to get file + /// + /// + private string _uri; + [DataMember(Name = "uri")] + public string Uri + { + get + { + return this._uri; + } + + set + { + int index = value.IndexOfAny(new char[] { '#', '?' }); + this._uri = index > -1 ? value.Substring(0, index) : value; + } + } + + /// + /// Size to truncate file + /// + [DataMember(Name = "size")] + public long Size { get; set; } + + /// + /// Data to write in file + /// + [DataMember(Name = "data")] + public string Data { get; set; } + + /// + /// Position the writing starts with + /// + [DataMember(Name = "position")] + public int Position { get; set; } + + /// + /// Type of file system requested + /// + [DataMember(Name = "type")] + public int FileSystemType { get; set; } + + /// + /// New file/directory name + /// + [DataMember(Name = "newName")] + public string NewName { get; set; } + + /// + /// Destination directory to copy/move file/directory + /// + [DataMember(Name = "parent")] + public string Parent { get; set; } + + /// + /// Options for getFile/getDirectory methods + /// + [DataMember(Name = "options")] + public CreatingOptions CreatingOpt { get; set; } + + /// + /// Creates options object with default parameters + /// + public FileOptions() + { + this.SetDefaultValues(new StreamingContext()); + } + + /// + /// Initializes default values for class fields. + /// Implemented in separate method because default constructor is not invoked during deserialization. + /// + /// + [OnDeserializing()] + public void SetDefaultValues(StreamingContext context) + { + this.Encoding = "UTF-8"; + this.FilePath = ""; + this.FileSystemType = -1; + } + } + + /// + /// Stores image info + /// + [DataContract] + public class FileMetadata + { + [DataMember(Name = "fileName")] + public string FileName { get; set; } + + [DataMember(Name = "fullPath")] + public string FullPath { get; set; } + + [DataMember(Name = "type")] + public string Type { get; set; } + + [DataMember(Name = "lastModifiedDate")] + public string LastModifiedDate { get; set; } + + [DataMember(Name = "size")] + public long Size { get; set; } + + public FileMetadata(string filePath) + { + if (string.IsNullOrEmpty(filePath)) + { + throw new FileNotFoundException("File doesn't exist"); + } + + this.FullPath = filePath; + this.Size = 0; + this.FileName = string.Empty; + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + bool IsFile = isoFile.FileExists(filePath); + bool IsDirectory = isoFile.DirectoryExists(filePath); + + if (!IsDirectory) + { + if (!IsFile) // special case, if isoFile cannot find it, it might still be part of the app-package + { + // attempt to get it from the resources + + Uri fileUri = new Uri(filePath, UriKind.Relative); + StreamResourceInfo streamInfo = Application.GetResourceStream(fileUri); + if (streamInfo != null) + { + this.Size = streamInfo.Stream.Length; + this.FileName = filePath.Substring(filePath.LastIndexOf("/") + 1); + } + else + { + throw new FileNotFoundException("File doesn't exist"); + } + } + else + { + using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.Read, isoFile)) + { + this.Size = stream.Length; + } + + this.FileName = System.IO.Path.GetFileName(filePath); + this.LastModifiedDate = isoFile.GetLastWriteTime(filePath).DateTime.ToString(); + } + } + + this.Type = MimeTypeMapper.GetMimeType(this.FileName); + } + } + } + + /// + /// Represents file or directory modification metadata + /// + [DataContract] + public class ModificationMetadata + { + /// + /// Modification time + /// + [DataMember] + public string modificationTime { get; set; } + } + + /// + /// Represents file or directory entry + /// + [DataContract] + public class FileEntry + { + + /// + /// File type + /// + [DataMember(Name = "isFile")] + public bool IsFile { get; set; } + + /// + /// Directory type + /// + [DataMember(Name = "isDirectory")] + public bool IsDirectory { get; set; } + + /// + /// File/directory name + /// + [DataMember(Name = "name")] + public string Name { get; set; } + + /// + /// Full path to file/directory + /// + [DataMember(Name = "fullPath")] + public string FullPath { get; set; } + + /// + /// URI encoded fullpath + /// + [DataMember(Name = "nativeURL")] + public string NativeURL + { + set { } + get + { + string escaped = Uri.EscapeUriString(this.FullPath); + escaped = escaped.Replace("//", "/"); + if (escaped.StartsWith("/")) + { + escaped = escaped.Insert(0, "/"); + } + return escaped; + } + } + + public bool IsResource { get; set; } + + public static FileEntry GetEntry(string filePath, bool bIsRes=false) + { + FileEntry entry = null; + try + { + entry = new FileEntry(filePath, bIsRes); + + } + catch (Exception ex) + { + Debug.WriteLine("Exception in GetEntry for filePath :: " + filePath + " " + ex.Message); + } + return entry; + } + + /// + /// Creates object and sets necessary properties + /// + /// + public FileEntry(string filePath, bool bIsRes = false) + { + if (string.IsNullOrEmpty(filePath)) + { + throw new ArgumentException(); + } + + if(filePath.Contains(" ")) + { + Debug.WriteLine("FilePath with spaces :: " + filePath); + } + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + IsResource = bIsRes; + IsFile = isoFile.FileExists(filePath); + IsDirectory = isoFile.DirectoryExists(filePath); + if (IsFile) + { + this.Name = Path.GetFileName(filePath); + } + else if (IsDirectory) + { + this.Name = this.GetDirectoryName(filePath); + if (string.IsNullOrEmpty(Name)) + { + this.Name = "/"; + } + } + else + { + if (IsResource) + { + this.Name = Path.GetFileName(filePath); + } + else + { + throw new FileNotFoundException(); + } + } + + try + { + this.FullPath = filePath.Replace('\\', '/'); // new Uri(filePath).LocalPath; + } + catch (Exception) + { + this.FullPath = filePath; + } + } + } + + /// + /// Extracts directory name from path string + /// Path should refer to a directory, for example \foo\ or /foo. + /// + /// + /// + private string GetDirectoryName(string path) + { + if (String.IsNullOrEmpty(path)) + { + return path; + } + + string[] split = path.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries); + if (split.Length < 1) + { + return null; + } + else + { + return split[split.Length - 1]; + } + } + } + + + /// + /// Represents info about requested file system + /// + [DataContract] + public class FileSystemInfo + { + /// + /// file system type + /// + [DataMember(Name = "name", IsRequired = true)] + public string Name { get; set; } + + /// + /// Root directory entry + /// + [DataMember(Name = "root", EmitDefaultValue = false)] + public FileEntry Root { get; set; } + + /// + /// Creates class instance + /// + /// + /// Root directory + public FileSystemInfo(string name, FileEntry rootEntry = null) + { + Name = name; + Root = rootEntry; + } + } + + [DataContract] + public class CreatingOptions + { + /// + /// Create file/directory if is doesn't exist + /// + [DataMember(Name = "create")] + public bool Create { get; set; } + + /// + /// Generate an exception if create=true and file/directory already exists + /// + [DataMember(Name = "exclusive")] + public bool Exclusive { get; set; } + + + } + + // returns null value if it fails. + private string[] getOptionStrings(string options) + { + string[] optStings = null; + try + { + optStings = JSON.JsonHelper.Deserialize(options); + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), CurrentCommandCallbackId); + } + return optStings; + } + + /// + /// Gets amount of free space available for Isolated Storage + /// + /// No options is needed for this method + public void getFreeDiskSpace(string options) + { + string callbackId = getOptionStrings(options)[0]; + + try + { + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, isoFile.AvailableFreeSpace), callbackId); + } + } + catch (IsolatedStorageException) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + + /// + /// Check if file exists + /// + /// File path + public void testFileExists(string options) + { + IsDirectoryOrFileExist(options, false); + } + + /// + /// Check if directory exists + /// + /// directory name + public void testDirectoryExists(string options) + { + IsDirectoryOrFileExist(options, true); + } + + /// + /// Check if file or directory exist + /// + /// File path/Directory name + /// Flag to recognize what we should check + public void IsDirectoryOrFileExist(string options, bool isDirectory) + { + string[] args = getOptionStrings(options); + string callbackId = args[1]; + FileOptions fileOptions = JSON.JsonHelper.Deserialize(args[0]); + string filePath = args[0]; + + if (fileOptions == null) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + } + + try + { + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + bool isExist; + if (isDirectory) + { + isExist = isoFile.DirectoryExists(fileOptions.DirectoryName); + } + else + { + isExist = isoFile.FileExists(fileOptions.FilePath); + } + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, isExist), callbackId); + } + } + catch (IsolatedStorageException) // default handler throws INVALID_MODIFICATION_ERR + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + } + } + + } + + public void readAsDataURL(string options) + { + string[] optStrings = getOptionStrings(options); + string filePath = optStrings[0]; + int startPos = int.Parse(optStrings[1]); + int endPos = int.Parse(optStrings[2]); + string callbackId = optStrings[3]; + + if (filePath != null) + { + try + { + string base64URL = null; + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (!isoFile.FileExists(filePath)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + return; + } + string mimeType = MimeTypeMapper.GetMimeType(filePath); + + using (IsolatedStorageFileStream stream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read)) + { + string base64String = GetFileContent(stream); + base64URL = "data:" + mimeType + ";base64," + base64String; + } + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, base64URL), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + } + + private byte[] readFileBytes(string filePath,int startPos,int endPos, IsolatedStorageFile isoFile) + { + byte[] buffer; + using (IsolatedStorageFileStream reader = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read)) + { + if (startPos < 0) + { + startPos = Math.Max((int)reader.Length + startPos, 0); + } + else if (startPos > 0) + { + startPos = Math.Min((int)reader.Length, startPos); + } + if (endPos > 0) + { + endPos = Math.Min((int)reader.Length, endPos); + } + else if (endPos < 0) + { + endPos = Math.Max(endPos + (int)reader.Length, 0); + } + + buffer = new byte[endPos - startPos]; + reader.Seek(startPos, SeekOrigin.Begin); + reader.Read(buffer, 0, buffer.Length); + } + + return buffer; + } + + public void readAsArrayBuffer(string options) + { + string[] optStrings = getOptionStrings(options); + string filePath = optStrings[0]; + int startPos = int.Parse(optStrings[1]); + int endPos = int.Parse(optStrings[2]); + string callbackId = optStrings[3]; + + try + { + byte[] buffer; + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (!isoFile.FileExists(filePath)) + { + readResourceAsText(options); + return; + } + buffer = readFileBytes(filePath, startPos, endPos, isoFile); + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, buffer), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + + public void readAsBinaryString(string options) + { + string[] optStrings = getOptionStrings(options); + string filePath = optStrings[0]; + int startPos = int.Parse(optStrings[1]); + int endPos = int.Parse(optStrings[2]); + string callbackId = optStrings[3]; + + try + { + string result; + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (!isoFile.FileExists(filePath)) + { + readResourceAsText(options); + return; + } + + byte[] buffer = readFileBytes(filePath, startPos, endPos, isoFile); + result = System.Text.Encoding.GetEncoding("iso-8859-1").GetString(buffer, 0, buffer.Length); + + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, result), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + + public void readAsText(string options) + { + string[] optStrings = getOptionStrings(options); + string filePath = optStrings[0]; + string encStr = optStrings[1]; + int startPos = int.Parse(optStrings[2]); + int endPos = int.Parse(optStrings[3]); + string callbackId = optStrings[4]; + + try + { + string text = ""; + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (!isoFile.FileExists(filePath)) + { + readResourceAsText(options); + return; + } + Encoding encoding = Encoding.GetEncoding(encStr); + + byte[] buffer = this.readFileBytes(filePath, startPos, endPos, isoFile); + text = encoding.GetString(buffer, 0, buffer.Length); + } + + // JIRA: https://issues.apache.org/jira/browse/CB-8792 + // Need to perform additional serialization here because NativeExecution is always trying + // to do JSON.parse() on command result. This leads to issue when trying to read JSON files + var resultText = JsonHelper.Serialize(text); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, resultText), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + + /// + /// Reads application resource as a text + /// + /// Path to a resource + public void readResourceAsText(string options) + { + string[] optStrings = getOptionStrings(options); + string pathToResource = optStrings[0]; + string encStr = optStrings[1]; + int start = int.Parse(optStrings[2]); + int endMarker = int.Parse(optStrings[3]); + string callbackId = optStrings[4]; + + try + { + if (pathToResource.StartsWith("/")) + { + pathToResource = pathToResource.Remove(0, 1); + } + + var resource = Application.GetResourceStream(new Uri(pathToResource, UriKind.Relative)); + + if (resource == null) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + return; + } + + string text; + StreamReader streamReader = new StreamReader(resource.Stream); + text = streamReader.ReadToEnd(); + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, text), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + + public void truncate(string options) + { + string[] optStrings = getOptionStrings(options); + + string filePath = optStrings[0]; + int size = int.Parse(optStrings[1]); + string callbackId = optStrings[2]; + + try + { + long streamLength = 0; + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (!isoFile.FileExists(filePath)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + return; + } + + using (FileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.ReadWrite, isoFile)) + { + if (0 <= size && size <= stream.Length) + { + stream.SetLength(size); + } + streamLength = stream.Length; + } + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, streamLength), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + + //write:[filePath,data,position,isBinary,callbackId] + public void write(string options) + { + string[] optStrings = getOptionStrings(options); + + string filePath = optStrings[0]; + string data = optStrings[1]; + int position = int.Parse(optStrings[2]); + bool isBinary = bool.Parse(optStrings[3]); + string callbackId = optStrings[4]; + + try + { + if (string.IsNullOrEmpty(data)) + { + Debug.WriteLine("Expected some data to be send in the write command to {0}", filePath); + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + return; + } + + byte[] dataToWrite = isBinary ? JSON.JsonHelper.Deserialize(data) : + System.Text.Encoding.UTF8.GetBytes(data); + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + // create the file if not exists + if (!isoFile.FileExists(filePath)) + { + var file = isoFile.CreateFile(filePath); + file.Close(); + } + + using (FileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.ReadWrite, isoFile)) + { + if (0 <= position && position <= stream.Length) + { + stream.SetLength(position); + } + using (BinaryWriter writer = new BinaryWriter(stream)) + { + writer.Seek(0, SeekOrigin.End); + writer.Write(dataToWrite); + } + } + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, dataToWrite.Length), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + + /// + /// Look up metadata about this entry. + /// + /// filePath to entry + public void getMetadata(string options) + { + string[] optStings = getOptionStrings(options); + string filePath = optStings[0]; + string callbackId = optStings[1]; + + if (filePath != null) + { + try + { + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (isoFile.FileExists(filePath)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, + new ModificationMetadata() { modificationTime = isoFile.GetLastWriteTime(filePath).DateTime.ToString() }), callbackId); + } + else if (isoFile.DirectoryExists(filePath)) + { + string modTime = isoFile.GetLastWriteTime(filePath).DateTime.ToString(); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new ModificationMetadata() { modificationTime = modTime }), callbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + } + + } + } + catch (IsolatedStorageException) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + + } + + + /// + /// Returns a File that represents the current state of the file that this FileEntry represents. + /// + /// filePath to entry + /// + public void getFileMetadata(string options) + { + string[] optStings = getOptionStrings(options); + string filePath = optStings[0]; + string callbackId = optStings[1]; + + if (!string.IsNullOrEmpty(filePath)) + { + try + { + FileMetadata metaData = new FileMetadata(filePath); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, metaData), callbackId); + } + catch (IsolatedStorageException) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId); + } + } + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + } + } + + /// + /// Look up the parent DirectoryEntry containing this Entry. + /// If this Entry is the root of IsolatedStorage, its parent is itself. + /// + /// + public void getParent(string options) + { + string[] optStings = getOptionStrings(options); + string filePath = optStings[0]; + string callbackId = optStings[1]; + + if (filePath != null) + { + try + { + if (string.IsNullOrEmpty(filePath)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId); + return; + } + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + FileEntry entry; + + if (isoFile.FileExists(filePath) || isoFile.DirectoryExists(filePath)) + { + + + string path = this.GetParentDirectory(filePath); + entry = FileEntry.GetEntry(path); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry),callbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId); + } + + } + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId); + } + } + } + } + + public void remove(string options) + { + string[] args = getOptionStrings(options); + string filePath = args[0]; + string callbackId = args[1]; + + if (filePath != null) + { + try + { + if (filePath == "/" || filePath == "" || filePath == @"\") + { + throw new Exception("Cannot delete root file system") ; + } + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (isoFile.FileExists(filePath)) + { + isoFile.DeleteFile(filePath); + } + else + { + if (isoFile.DirectoryExists(filePath)) + { + isoFile.DeleteDirectory(filePath); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId); + return; + } + } + DispatchCommandResult(new PluginResult(PluginResult.Status.OK),callbackId); + } + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId); + } + } + } + } + + public void removeRecursively(string options) + { + string[] args = getOptionStrings(options); + string filePath = args[0]; + string callbackId = args[1]; + + if (filePath != null) + { + if (string.IsNullOrEmpty(filePath)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId); + } + else + { + if (removeDirRecursively(filePath, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId); + } + } + } + } + + public void readEntries(string options) + { + string[] args = getOptionStrings(options); + string filePath = args[0]; + string callbackId = args[1]; + + if (filePath != null) + { + try + { + if (string.IsNullOrEmpty(filePath)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId); + return; + } + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (isoFile.DirectoryExists(filePath)) + { + string path = File.AddSlashToDirectory(filePath); + List entries = new List(); + string[] files = isoFile.GetFileNames(path + "*"); + string[] dirs = isoFile.GetDirectoryNames(path + "*"); + foreach (string file in files) + { + entries.Add(FileEntry.GetEntry(path + file)); + } + foreach (string dir in dirs) + { + entries.Add(FileEntry.GetEntry(path + dir + "/")); + } + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entries),callbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId); + } + } + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId); + } + } + } + } + + public void requestFileSystem(string options) + { + // TODO: try/catch + string[] optVals = getOptionStrings(options); + //FileOptions fileOptions = new FileOptions(); + int fileSystemType = int.Parse(optVals[0]); + double size = double.Parse(optVals[1]); + string callbackId = optVals[2]; + + + IsolatedStorageFile.GetUserStoreForApplication(); + + if (size > (10 * 1024 * 1024)) // 10 MB, compier will clean this up! + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, QUOTA_EXCEEDED_ERR), callbackId); + return; + } + + try + { + if (size != 0) + { + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + long availableSize = isoFile.AvailableFreeSpace; + if (size > availableSize) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, QUOTA_EXCEEDED_ERR), callbackId); + return; + } + } + } + + if (fileSystemType == PERSISTENT) + { + // TODO: this should be in it's own folder to prevent overwriting of the app assets, which are also in ISO + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("persistent", FileEntry.GetEntry("/"))), callbackId); + } + else if (fileSystemType == TEMPORARY) + { + using (IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (!isoStorage.FileExists(TMP_DIRECTORY_NAME)) + { + isoStorage.CreateDirectory(TMP_DIRECTORY_NAME); + } + } + + string tmpFolder = "/" + TMP_DIRECTORY_NAME + "/"; + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("temporary", FileEntry.GetEntry(tmpFolder))), callbackId); + } + else if (fileSystemType == RESOURCE) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("resource")), callbackId); + } + else if (fileSystemType == APPLICATION) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("application")), callbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId); + } + + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId); + } + } + } + + public void resolveLocalFileSystemURI(string options) + { + + string[] optVals = getOptionStrings(options); + string uri = optVals[0].Split('?')[0]; + string callbackId = optVals[1]; + + if (uri != null) + { + // a single '/' is valid, however, '/someDir' is not, but '/tmp//somedir' and '///someDir' are valid + if (uri.StartsWith("/") && uri.IndexOf("//") < 0 && uri != "/") + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId); + return; + } + try + { + // fix encoded spaces + string path = Uri.UnescapeDataString(uri); + + FileEntry uriEntry = FileEntry.GetEntry(path); + if (uriEntry != null) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, uriEntry), callbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + } + } + catch (Exception ex) + { + if (!this.HandleException(ex, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId); + } + } + } + } + + public void copyTo(string options) + { + TransferTo(options, false); + } + + public void moveTo(string options) + { + TransferTo(options, true); + } + + public void getFile(string options) + { + GetFileOrDirectory(options, false); + } + + public void getDirectory(string options) + { + GetFileOrDirectory(options, true); + } + + #region internal functionality + + /// + /// Retrieves the parent directory name of the specified path, + /// + /// Path + /// Parent directory name + private string GetParentDirectory(string path) + { + if (String.IsNullOrEmpty(path) || path == "/") + { + return "/"; + } + + if (path.EndsWith(@"/") || path.EndsWith(@"\")) + { + return this.GetParentDirectory(Path.GetDirectoryName(path)); + } + + string result = Path.GetDirectoryName(path); + if (result == null) + { + result = "/"; + } + + return result; + } + + private bool removeDirRecursively(string fullPath,string callbackId) + { + try + { + if (fullPath == "/") + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId); + return false; + } + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (isoFile.DirectoryExists(fullPath)) + { + string tempPath = File.AddSlashToDirectory(fullPath); + string[] files = isoFile.GetFileNames(tempPath + "*"); + if (files.Length > 0) + { + foreach (string file in files) + { + isoFile.DeleteFile(tempPath + file); + } + } + string[] dirs = isoFile.GetDirectoryNames(tempPath + "*"); + if (dirs.Length > 0) + { + foreach (string dir in dirs) + { + if (!removeDirRecursively(tempPath + dir, callbackId)) + { + return false; + } + } + } + isoFile.DeleteDirectory(fullPath); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId); + } + } + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId); + return false; + } + } + return true; + } + + private bool CanonicalCompare(string pathA, string pathB) + { + string a = pathA.Replace("//", "/"); + string b = pathB.Replace("//", "/"); + + return a.Equals(b, StringComparison.OrdinalIgnoreCase); + } + + /* + * copyTo:["fullPath","parent", "newName"], + * moveTo:["fullPath","parent", "newName"], + */ + private void TransferTo(string options, bool move) + { + // TODO: try/catch + string[] optStrings = getOptionStrings(options); + string fullPath = optStrings[0]; + string parent = optStrings[1]; + string newFileName = optStrings[2]; + string callbackId = optStrings[3]; + + char[] invalids = Path.GetInvalidPathChars(); + + if (newFileName.IndexOfAny(invalids) > -1 || newFileName.IndexOf(":") > -1 ) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId); + return; + } + + try + { + if ((parent == null) || (string.IsNullOrEmpty(parent)) || (string.IsNullOrEmpty(fullPath))) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + return; + } + + string parentPath = File.AddSlashToDirectory(parent); + string currentPath = fullPath; + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + bool isFileExist = isoFile.FileExists(currentPath); + bool isDirectoryExist = isoFile.DirectoryExists(currentPath); + bool isParentExist = isoFile.DirectoryExists(parentPath); + + if ( ( !isFileExist && !isDirectoryExist ) || !isParentExist ) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + return; + } + string newName; + string newPath; + if (isFileExist) + { + newName = (string.IsNullOrEmpty(newFileName)) + ? Path.GetFileName(currentPath) + : newFileName; + + newPath = Path.Combine(parentPath, newName); + + // sanity check .. + // cannot copy file onto itself + if (CanonicalCompare(newPath,currentPath)) //(parent + newFileName)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId); + return; + } + else if (isoFile.DirectoryExists(newPath)) + { + // there is already a folder with the same name, operation is not allowed + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId); + return; + } + else if (isoFile.FileExists(newPath)) + { // remove destination file if exists, in other case there will be exception + isoFile.DeleteFile(newPath); + } + + if (move) + { + isoFile.MoveFile(currentPath, newPath); + } + else + { + isoFile.CopyFile(currentPath, newPath, true); + } + } + else + { + newName = (string.IsNullOrEmpty(newFileName)) + ? currentPath + : newFileName; + + newPath = Path.Combine(parentPath, newName); + + if (move) + { + // remove destination directory if exists, in other case there will be exception + // target directory should be empty + if (!newPath.Equals(currentPath) && isoFile.DirectoryExists(newPath)) + { + isoFile.DeleteDirectory(newPath); + } + + isoFile.MoveDirectory(currentPath, newPath); + } + else + { + CopyDirectory(currentPath, newPath, isoFile); + } + } + FileEntry entry = FileEntry.GetEntry(newPath); + if (entry != null) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry), callbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + } + } + + } + catch (Exception ex) + { + if (!this.HandleException(ex, callbackId)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId); + } + } + } + + private bool HandleException(Exception ex, string cbId="") + { + bool handled = false; + string callbackId = String.IsNullOrEmpty(cbId) ? this.CurrentCommandCallbackId : cbId; + if (ex is SecurityException) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, SECURITY_ERR), callbackId); + handled = true; + } + else if (ex is FileNotFoundException) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + handled = true; + } + else if (ex is ArgumentException) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId); + handled = true; + } + else if (ex is IsolatedStorageException) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId); + handled = true; + } + else if (ex is DirectoryNotFoundException) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + handled = true; + } + return handled; + } + + private void CopyDirectory(string sourceDir, string destDir, IsolatedStorageFile isoFile) + { + string path = File.AddSlashToDirectory(sourceDir); + + bool bExists = isoFile.DirectoryExists(destDir); + + if (!bExists) + { + isoFile.CreateDirectory(destDir); + } + + destDir = File.AddSlashToDirectory(destDir); + + string[] files = isoFile.GetFileNames(path + "*"); + + if (files.Length > 0) + { + foreach (string file in files) + { + isoFile.CopyFile(path + file, destDir + file,true); + } + } + string[] dirs = isoFile.GetDirectoryNames(path + "*"); + if (dirs.Length > 0) + { + foreach (string dir in dirs) + { + CopyDirectory(path + dir, destDir + dir, isoFile); + } + } + } + + private string RemoveExtraSlash(string path) { + if (path.StartsWith("//")) { + path = path.Remove(0, 1); + path = RemoveExtraSlash(path); + } + return path; + } + + private string ResolvePath(string parentPath, string path) + { + string absolutePath = null; + + if (path.Contains("..")) + { + if (parentPath.Length > 1 && parentPath.StartsWith("/") && parentPath !="/") + { + parentPath = RemoveExtraSlash(parentPath); + } + + string fullPath = Path.GetFullPath(Path.Combine(parentPath, path)); + absolutePath = fullPath.Replace(Path.GetPathRoot(fullPath), @"//"); + } + else + { + absolutePath = Path.Combine(parentPath + "/", path); + } + return absolutePath; + } + + private void GetFileOrDirectory(string options, bool getDirectory) + { + FileOptions fOptions = new FileOptions(); + string[] args = getOptionStrings(options); + + fOptions.FullPath = args[0]; + fOptions.Path = args[1]; + + string callbackId = args[3]; + + try + { + fOptions.CreatingOpt = JSON.JsonHelper.Deserialize(args[2]); + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + return; + } + + try + { + if ((string.IsNullOrEmpty(fOptions.Path)) || (string.IsNullOrEmpty(fOptions.FullPath))) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + return; + } + + string path; + + if (fOptions.Path.Split(':').Length > 2) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId); + return; + } + + try + { + path = ResolvePath(fOptions.FullPath, fOptions.Path); + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId); + return; + } + + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + bool isFile = isoFile.FileExists(path); + bool isDirectory = isoFile.DirectoryExists(path); + bool create = (fOptions.CreatingOpt == null) ? false : fOptions.CreatingOpt.Create; + bool exclusive = (fOptions.CreatingOpt == null) ? false : fOptions.CreatingOpt.Exclusive; + if (create) + { + if (exclusive && (isoFile.FileExists(path) || isoFile.DirectoryExists(path))) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, PATH_EXISTS_ERR), callbackId); + return; + } + + // need to make sure the parent exists + // it is an error to create a directory whose immediate parent does not yet exist + // see issue: https://issues.apache.org/jira/browse/CB-339 + string[] pathParts = path.Split('/'); + string builtPath = pathParts[0]; + for (int n = 1; n < pathParts.Length - 1; n++) + { + builtPath += "/" + pathParts[n]; + if (!isoFile.DirectoryExists(builtPath)) + { + Debug.WriteLine(String.Format("Error :: Parent folder \"{0}\" does not exist, when attempting to create \"{1}\"",builtPath,path)); + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + return; + } + } + + if ((getDirectory) && (!isDirectory)) + { + isoFile.CreateDirectory(path); + } + else + { + if ((!getDirectory) && (!isFile)) + { + + IsolatedStorageFileStream fileStream = isoFile.CreateFile(path); + fileStream.Close(); + } + } + } + else // (not create) + { + if ((!isFile) && (!isDirectory)) + { + if (path.IndexOf("//www") == 0) + { + Uri fileUri = new Uri(path.Remove(0,2), UriKind.Relative); + StreamResourceInfo streamInfo = Application.GetResourceStream(fileUri); + if (streamInfo != null) + { + FileEntry _entry = FileEntry.GetEntry(fileUri.OriginalString,true); + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, _entry), callbackId); + + //using (BinaryReader br = new BinaryReader(streamInfo.Stream)) + //{ + // byte[] data = br.ReadBytes((int)streamInfo.Stream.Length); + + //} + + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + } + + + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + } + return; + } + if (((getDirectory) && (!isDirectory)) || ((!getDirectory) && (!isFile))) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, TYPE_MISMATCH_ERR), callbackId); + return; + } + } + FileEntry entry = FileEntry.GetEntry(path); + if (entry != null) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry), callbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId); + } + } + } + catch (Exception ex) + { + if (!this.HandleException(ex)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId); + } + } + } + + private static string AddSlashToDirectory(string dirPath) + { + if (dirPath.EndsWith("/")) + { + return dirPath; + } + else + { + return dirPath + "/"; + } + } + + /// + /// Returns file content in a form of base64 string + /// + /// File stream + /// Base64 representation of the file + private string GetFileContent(Stream stream) + { + int streamLength = (int)stream.Length; + byte[] fileData = new byte[streamLength + 1]; + stream.Read(fileData, 0, streamLength); + stream.Close(); + return Convert.ToBase64String(fileData); + } + + #endregion + + } +} diff --git a/mobile/plugins/cordova-plugin-file/tests/plugin.xml b/mobile/plugins/cordova-plugin-file/tests/plugin.xml new file mode 100644 index 0000000..29e531f --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/tests/plugin.xml @@ -0,0 +1,44 @@ + + + + + + Cordova File Plugin Tests + Apache 2.0 + + + + + + + + + + + + + diff --git a/mobile/plugins/cordova-plugin-file/tests/src/android/TestContentProvider.java b/mobile/plugins/cordova-plugin-file/tests/src/android/TestContentProvider.java new file mode 100644 index 0000000..9eba0d0 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/tests/src/android/TestContentProvider.java @@ -0,0 +1,93 @@ +/* + 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.cordova.file.test; + +import android.content.ContentProvider; +import android.net.Uri; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import android.content.ContentValues; +import android.database.Cursor; +import android.os.ParcelFileDescriptor; + +import org.apache.cordova.CordovaResourceApi; + +import java.io.IOException; +import java.util.HashMap; + +public class TestContentProvider extends ContentProvider { + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + String fileName = uri.getQueryParameter("realPath"); + if (fileName == null) { + fileName = uri.getPath(); + } + if (fileName == null || fileName.length() < 1) { + throw new FileNotFoundException(); + } + CordovaResourceApi resourceApi = new CordovaResourceApi(getContext(), null); + try { + File f = File.createTempFile("test-content-provider", ".tmp"); + resourceApi.copyResource(Uri.parse("file:///android_asset" + fileName), Uri.fromFile(f)); + return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); + } catch (FileNotFoundException e) { + throw e; + } catch (IOException e) { + e.printStackTrace(); + throw new FileNotFoundException("IO error: " + e.toString()); + } + } + + @Override + public boolean onCreate() { + return false; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + throw new UnsupportedOperationException(); + } + + @Override + public String getType(Uri uri) { + return "text/html"; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException(); + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException(); + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException(); + } + + +} diff --git a/mobile/plugins/cordova-plugin-file/tests/tests.js b/mobile/plugins/cordova-plugin-file/tests/tests.js new file mode 100644 index 0000000..acdcfa0 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/tests/tests.js @@ -0,0 +1,4012 @@ +/* + * + * 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. + * + */ + +/* jshint jasmine: true */ +/* global WebKitBlobBuilder */ + +exports.defineAutoTests = function () { + var isBrowser = (cordova.platformId === "browser"); + // Use feature detection to determine current browser instead of checking user-agent + var isChrome = isBrowser && window.webkitRequestFileSystem && window.webkitResolveLocalFileSystemURL; + var isIE = isBrowser && (window.msIndexedDB); + var isIndexedDBShim = isBrowser && !isChrome; // Firefox and IE for example + + var isWindows = (cordova.platformId === "windows" || cordova.platformId === "windows8"); + + var MEDIUM_TIMEOUT = 15000; + + describe('File API', function () { + // Adding a Jasmine helper matcher, to report errors when comparing to FileError better. + var fileErrorMap = { + 1 : 'NOT_FOUND_ERR', + 2 : 'SECURITY_ERR', + 3 : 'ABORT_ERR', + 4 : 'NOT_READABLE_ERR', + 5 : 'ENCODING_ERR', + 6 : 'NO_MODIFICATION_ALLOWED_ERR', + 7 : 'INVALID_STATE_ERR', + 8 : 'SYNTAX_ERR', + 9 : 'INVALID_MODIFICATION_ERR', + 10 : 'QUOTA_EXCEEDED_ERR', + 11 : 'TYPE_MISMATCH_ERR', + 12 : 'PATH_EXISTS_ERR' + }, + root, + temp_root, + persistent_root; + beforeEach(function (done) { + // Custom Matchers + jasmine.Expectation.addMatchers({ + toBeFileError : function () { + return { + compare : function (error, code) { + var pass = error.code === code; + return { + pass : pass, + message : 'Expected FileError with code ' + fileErrorMap[error.code] + ' (' + error.code + ') to be ' + fileErrorMap[code] + '(' + code + ')' + }; + } + }; + }, + toCanonicallyMatch : function () { + return { + compare : function (currentPath, path) { + var a = path.split("/").join("").split("\\").join(""), + b = currentPath.split("/").join("").split("\\").join(""), + pass = a === b; + return { + pass : pass, + message : 'Expected paths to match : ' + path + ' should be ' + currentPath + }; + } + }; + }, + toFailWithMessage : function () { + return { + compare : function (error, message) { + var pass = false; + return { + pass : pass, + message : message + }; + } + }; + }, + toBeDataUrl: function () { + return { + compare : function (url) { + var pass = false; + // "data:application/octet-stream;base64," + var header = url.substr(0, url.indexOf(',')); + var headerParts = header.split(/[:;]/); + if (headerParts.length === 3 && + headerParts[0] === 'data' && + headerParts[2] === 'base64') { + pass = true; + } + var message = 'Expected ' + url + ' to be a valid data url. ' + header + ' is not valid header for data uris'; + return { + pass : pass, + message : message + }; + } + }; + } + }); + //Define global variables + var onError = function (e) { + console.log('[ERROR] Problem setting up root filesystem for test running! Error to follow.'); + console.log(JSON.stringify(e)); + }; + window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) { + root = fileSystem.root; + // set in file.tests.js + persistent_root = root; + window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, function (fileSystem) { + temp_root = fileSystem.root; + // set in file.tests.js + done(); + }, onError); + }, onError); + }); + // HELPER FUNCTIONS + // deletes specified file or directory + var deleteEntry = function (name, success, error) { + // deletes entry, if it exists + // entry.remove success callback is required: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#the-entry-interface + success = success || function() {}; + error = error || failed.bind(null, success, 'deleteEntry failed.'); + + window.resolveLocalFileSystemURL(root.toURL() + '/' + name, function (entry) { + if (entry.isDirectory === true) { + entry.removeRecursively(success, error); + } else { + entry.remove(success, error); + } + }, success); + }; + // deletes file, if it exists, then invokes callback + var deleteFile = function (fileName, callback) { + // entry.remove success callback is required: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#the-entry-interface + callback = callback || function() {}; + + root.getFile(fileName, null, // remove file system entry + function (entry) { + entry.remove(callback, function () { + console.log('[ERROR] deleteFile cleanup method invoked fail callback.'); + }); + }, // doesn't exist + callback); + }; + // deletes and re-creates the specified file + var createFile = function (fileName, success, error) { + deleteEntry(fileName, function () { + root.getFile(fileName, { + create : true + }, success, error); + }, error); + }; + // deletes and re-creates the specified directory + var createDirectory = function (dirName, success, error) { + deleteEntry(dirName, function () { + root.getDirectory(dirName, { + create : true + }, success, error); + }, error); + }; + function failed(done, msg, error) { + var info = typeof msg == 'undefined' ? 'Unexpected error callback' : msg; + var codeMsg = (error && error.code) ? (': ' + fileErrorMap[error.code]) : ''; + expect(true).toFailWithMessage(info + '\n' + JSON.stringify(error) + codeMsg); + done(); + } + var succeed = function (done, msg) { + var info = typeof msg == 'undefined' ? 'Unexpected success callback' : msg; + expect(true).toFailWithMessage(info); + done(); + }; + var joinURL = function (base, extension) { + if (base.charAt(base.length - 1) !== '/' && extension.charAt(0) !== '/') { + return base + '/' + extension; + } + if (base.charAt(base.length - 1) === '/' && extension.charAt(0) === '/') { + return base + extension.substring(1); + } + return base + extension; + }; + describe('FileError object', function () { + it("file.spec.1 should define FileError constants", function () { + expect(FileError.NOT_FOUND_ERR).toBe(1); + expect(FileError.SECURITY_ERR).toBe(2); + expect(FileError.ABORT_ERR).toBe(3); + expect(FileError.NOT_READABLE_ERR).toBe(4); + expect(FileError.ENCODING_ERR).toBe(5); + expect(FileError.NO_MODIFICATION_ALLOWED_ERR).toBe(6); + expect(FileError.INVALID_STATE_ERR).toBe(7); + expect(FileError.SYNTAX_ERR).toBe(8); + expect(FileError.INVALID_MODIFICATION_ERR).toBe(9); + expect(FileError.QUOTA_EXCEEDED_ERR).toBe(10); + expect(FileError.TYPE_MISMATCH_ERR).toBe(11); + expect(FileError.PATH_EXISTS_ERR).toBe(12); + }); + }); + describe('LocalFileSystem', function () { + it("file.spec.2 should define LocalFileSystem constants", function () { + expect(LocalFileSystem.TEMPORARY).toBe(0); + expect(LocalFileSystem.PERSISTENT).toBe(1); + }); + describe('window.requestFileSystem', function () { + it("file.spec.3 should be defined", function () { + expect(window.requestFileSystem).toBeDefined(); + }); + it("file.spec.4 should be able to retrieve a PERSISTENT file system", function (done) { + var win = function (fileSystem) { + expect(fileSystem).toBeDefined(); + expect(fileSystem.name).toBeDefined(); + if (isChrome) { + expect(fileSystem.name).toContain("Persistent"); + } else { + expect(fileSystem.name).toBe("persistent"); + } + expect(fileSystem.root).toBeDefined(); + expect(fileSystem.root.filesystem).toBeDefined(); + // Shouldn't use cdvfile by default. + expect(fileSystem.root.toURL()).not.toMatch(/^cdvfile:/); + // All DirectoryEntry URLs should always have a trailing slash. + expect(fileSystem.root.toURL()).toMatch(/\/$/); + done(); + }; + + // Request a little bit of space on the filesystem, unless we're running in a browser where that could cause a prompt. + var spaceRequired = isBrowser ? 0 : 1024; + + // retrieve PERSISTENT file system + window.requestFileSystem(LocalFileSystem.PERSISTENT, spaceRequired, win, failed.bind(null, done, 'window.requestFileSystem - Error retrieving PERSISTENT file system')); + }); + it("file.spec.5 should be able to retrieve a TEMPORARY file system", function (done) { + var win = function (fileSystem) { + expect(fileSystem).toBeDefined(); + if (isChrome) { + expect(fileSystem.name).toContain("Temporary"); + } else { + expect(fileSystem.name).toBe("temporary"); + } + expect(fileSystem.root).toBeDefined(); + expect(fileSystem.root.filesystem).toBeDefined(); + expect(fileSystem.root.filesystem).toBe(fileSystem); + done(); + }; + //retrieve TEMPORARY file system + window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, win, failed.bind(null, done, 'window.requestFileSystem - Error retrieving TEMPORARY file system')); + }); + it("file.spec.6 should error if you request a file system that is too large", function (done) { + if (isBrowser) { + /*window.requestFileSystem TEMPORARY and PERSISTENT filesystem quota is not limited in Chrome. + Firefox filesystem size is not limited but every 50MB request user permission. + IE10 allows up to 10mb of combined AppCache and IndexedDB used in implementation + of filesystem without prompting, once you hit that level you will be asked if you + want to allow it to be increased up to a max of 250mb per site. + So `size` parameter for `requestFileSystem` function does not affect on filesystem in Firefox and IE.*/ + pending(); + } + + var fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.QUOTA_EXCEEDED_ERR); + done(); + }; + //win = createWin('window.requestFileSystem'); + // Request the file system + window.requestFileSystem(LocalFileSystem.TEMPORARY, 1000000000000000, failed.bind(null, done, 'window.requestFileSystem - Error retrieving TEMPORARY file system'), fail); + }); + it("file.spec.7 should error out if you request a file system that does not exist", function (done) { + + var fail = function (error) { + expect(error).toBeDefined(); + if (isChrome) { + /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of SYNTAX_ERR(code: 8) + on requesting of a non-existant filesystem.*/ + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + } else { + expect(error).toBeFileError(FileError.SYNTAX_ERR); + } + done(); + }; + // Request the file system + window.requestFileSystem(-1, 0, succeed.bind(null, done, 'window.requestFileSystem'), fail); + }); + }); + describe('window.resolveLocalFileSystemURL', function () { + it("file.spec.8 should be defined", function () { + expect(window.resolveLocalFileSystemURL).toBeDefined(); + }); + it("file.spec.9 should resolve a valid file name", function (done) { + var fileName = 'file.spec.9'; + var win = function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.isFile).toBe(true); + expect(fileEntry.isDirectory).toBe(false); + expect(fileEntry.name).toCanonicallyMatch(fileName); + expect(fileEntry.toURL()).not.toMatch(/^cdvfile:/, 'should not use cdvfile URL'); + expect(fileEntry.toURL()).not.toMatch(/\/$/, 'URL should not end with a slash'); + // Clean-up + deleteEntry(fileName, done); + }; + createFile(fileName, function (entry) { + window.resolveLocalFileSystemURL(entry.toURL(), win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving file URL: ' + entry.toURL())); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName), failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.9.1 should resolve a file even with a terminating slash", function (done) { + var fileName = 'file.spec.9.1'; + var win = function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.isFile).toBe(true); + expect(fileEntry.isDirectory).toBe(false); + expect(fileEntry.name).toCanonicallyMatch(fileName); + expect(fileEntry.toURL()).not.toMatch(/^cdvfile:/, 'should not use cdvfile URL'); + expect(fileEntry.toURL()).not.toMatch(/\/$/, 'URL should not end with a slash'); + // Clean-up + deleteEntry(fileName, done); + }; + createFile(fileName, function (entry) { + var entryURL = entry.toURL() + '/'; + window.resolveLocalFileSystemURL(entryURL, win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving file URL: ' + entryURL)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName), failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.9.5 should resolve a directory", function (done) { + var fileName = 'file.spec.9.5'; + var win = function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.isFile).toBe(false); + expect(fileEntry.isDirectory).toBe(true); + expect(fileEntry.name).toCanonicallyMatch(fileName); + expect(fileEntry.toURL()).not.toMatch(/^cdvfile:/, 'should not use cdvfile URL'); + expect(fileEntry.toURL()).toMatch(/\/$/, 'URL end with a slash'); + // cleanup + deleteEntry(fileName, done); + }; + function gotDirectory(entry) { + // lookup file system entry + window.resolveLocalFileSystemURL(entry.toURL(), win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving directory URL: ' + entry.toURL())); + } + createDirectory(fileName, gotDirectory, failed.bind(null, done, 'createDirectory - Error creating directory: ' + fileName), failed.bind(null, done, 'createDirectory - Error creating directory: ' + fileName)); + }); + it("file.spec.9.6 should resolve a directory even without a terminating slash", function (done) { + var fileName = 'file.spec.9.6'; + var win = function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.isFile).toBe(false); + expect(fileEntry.isDirectory).toBe(true); + expect(fileEntry.name).toCanonicallyMatch(fileName); + expect(fileEntry.toURL()).not.toMatch(/^cdvfile:/, 'should not use cdvfile URL'); + expect(fileEntry.toURL()).toMatch(/\/$/, 'URL end with a slash'); + // cleanup + deleteEntry(fileName, done); + }; + function gotDirectory(entry) { + // lookup file system entry + var entryURL = entry.toURL(); + entryURL = entryURL.substring(0, entryURL.length - 1); + window.resolveLocalFileSystemURL(entryURL, win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving directory URL: ' + entryURL)); + } + createDirectory(fileName, gotDirectory, failed.bind(null, done, 'createDirectory - Error creating directory: ' + fileName), failed.bind(null, done, 'createDirectory - Error creating directory: ' + fileName)); + }); + + it("file.spec.9.7 should resolve a file with valid nativeURL", function (done) { + var fileName = "de.create.file", + win = function (entry) { + var path = entry.nativeURL.split('///')[1]; + expect(/\/{2,}/.test(path)).toBeFalsy(); + // cleanup + deleteEntry(entry.name, done); + }; + root.getFile(fileName, { + create: true + }, win, succeed.bind(null, done, 'root.getFile - Error unexpected callback, file should not exists: ' + fileName)); + }); + + it("file.spec.10 resolve valid file name with parameters", function (done) { + var fileName = "resolve.file.uri.params", + win = function (fileEntry) { + expect(fileEntry).toBeDefined(); + if (fileEntry.toURL().toLowerCase().substring(0, 10) === "cdvfile://") { + expect(fileEntry.fullPath).toBe("/" + fileName + "?1234567890"); + } + expect(fileEntry.name).toBe(fileName); + // cleanup + deleteEntry(fileName, done); + }; + // create a new file entry + createFile(fileName, function (entry) { + window.resolveLocalFileSystemURL(entry.toURL() + "?1234567890", win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving file URI: ' + entry.toURL())); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.11 should error (NOT_FOUND_ERR) when resolving (non-existent) invalid file name", function (done) { + var fileName = cordova.platformId === 'windowsphone' ? root.toURL() + "/" + "this.is.not.a.valid.file.txt" : joinURL(root.toURL(), "this.is.not.a.valid.file.txt"), + fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }; + // lookup file system entry + window.resolveLocalFileSystemURL(fileName, succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Error unexpected callback resolving file URI: ' + fileName), fail); + }); + it("file.spec.12 should error (ENCODING_ERR) when resolving invalid URI with leading /", function (done) { + var fileName = "/this.is.not.a.valid.url", + fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.ENCODING_ERR); + done(); + }; + // lookup file system entry + window.resolveLocalFileSystemURL(fileName, succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Error unexpected callback resolving file URI: ' + fileName), fail); + }); + }); + }); + //LocalFileSystem + describe('Metadata interface', function () { + it("file.spec.13 should exist and have the right properties", function () { + var metadata = new Metadata(); + expect(metadata).toBeDefined(); + expect(metadata.modificationTime).toBeDefined(); + }); + }); + describe('Flags interface', function () { + it("file.spec.14 should exist and have the right properties", function () { + var flags = new Flags(false, true); + expect(flags).toBeDefined(); + expect(flags.create).toBeDefined(); + expect(flags.create).toBe(false); + expect(flags.exclusive).toBeDefined(); + expect(flags.exclusive).toBe(true); + }); + }); + describe('FileSystem interface', function () { + it("file.spec.15 should have a root that is a DirectoryEntry", function (done) { + var win = function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(false); + expect(entry.isDirectory).toBe(true); + expect(entry.name).toBeDefined(); + expect(entry.fullPath).toBeDefined(); + expect(entry.getMetadata).toBeDefined(); + expect(entry.moveTo).toBeDefined(); + expect(entry.copyTo).toBeDefined(); + expect(entry.toURL).toBeDefined(); + expect(entry.remove).toBeDefined(); + expect(entry.getParent).toBeDefined(); + expect(entry.createReader).toBeDefined(); + expect(entry.getFile).toBeDefined(); + expect(entry.getDirectory).toBeDefined(); + expect(entry.removeRecursively).toBeDefined(); + done(); + }; + window.resolveLocalFileSystemURL(root.toURL(), win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving file URI: ' + root.toURL())); + }); + }); + describe('DirectoryEntry', function () { + it("file.spec.16 getFile: get Entry for file that does not exist", function (done) { + var fileName = "de.no.file", + fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }; + // create:false, exclusive:false, file does not exist + root.getFile(fileName, { + create : false + }, succeed.bind(null, done, 'root.getFile - Error unexpected callback, file should not exists: ' + fileName), fail); + }); + it("file.spec.17 getFile: create new file", function (done) { + var fileName = "de.create.file", + filePath = joinURL(root.fullPath, fileName), + win = function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(fileName); + expect(entry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(entry.name, done); + }; + // create:true, exclusive:false, file does not exist + root.getFile(fileName, { + create : true + }, win, succeed.bind(null, done, 'root.getFile - Error unexpected callback, file should not exists: ' + fileName)); + }); + it("file.spec.18 getFile: create new file (exclusive)", function (done) { + var fileName = "de.create.exclusive.file", + filePath = joinURL(root.fullPath, fileName), + win = function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toBe(fileName); + expect(entry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(entry.name, done); + }; + // create:true, exclusive:true, file does not exist + root.getFile(fileName, { + create : true, + exclusive : true + }, win, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName)); + }); + it("file.spec.19 getFile: create file that already exists", function (done) { + var fileName = "de.create.existing.file", + filePath = joinURL(root.fullPath, fileName); + + function win(entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(fileName); + expect(entry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(entry.name, done); + } + + function getFile(file) { + // create:true, exclusive:false, file exists + root.getFile(fileName, { + create : true + }, win, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName)); + } + + // create file to kick off it + root.getFile(fileName, { + create : true + }, getFile, failed.bind(null, done, 'root.getFile - Error on initial creating file: ' + fileName)); + }); + it("file.spec.20 getFile: create file that already exists (exclusive)", function (done) { + var fileName = "de.create.exclusive.existing.file", + existingFile; + + function fail(error) { + expect(error).toBeDefined(); + if (isChrome) { + /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of PATH_EXISTS_ERR(code: 12) + on trying to exclusively create a file, which already exists in Chrome.*/ + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + } else { + expect(error).toBeFileError(FileError.PATH_EXISTS_ERR); + } + // cleanup + deleteEntry(existingFile.name, done); + } + + function getFile(file) { + existingFile = file; + // create:true, exclusive:true, file exists + root.getFile(fileName, { + create : true, + exclusive : true + }, succeed.bind(null, done, 'root.getFile - getFile function - Error unexpected callback, file should exists: ' + fileName), fail); + } + + // create file to kick off it + root.getFile(fileName, { + create : true + }, getFile, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName)); + }); + it("file.spec.21 DirectoryEntry.getFile: get Entry for existing file", function (done) { + var fileName = "de.get.file", + filePath = joinURL(root.fullPath, fileName), + win = function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(fileName); + expect(entry.fullPath).toCanonicallyMatch(filePath); + expect(entry.filesystem).toBeDefined(); + expect(entry.filesystem).toBe(root.filesystem); + //clean up + deleteEntry(entry.name, done); + }, + getFile = function (file) { + // create:false, exclusive:false, file exists + root.getFile(fileName, { + create : false + }, win, failed.bind(null, done, 'root.getFile - Error getting file entry: ' + fileName)); + }; + // create file to kick off it + root.getFile(fileName, { + create : true + }, getFile, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName)); + }); + it("file.spec.22 DirectoryEntry.getFile: get FileEntry for invalid path", function (done) { + if (isBrowser) { + /*The plugin does not follow to ["8.3 Naming restrictions"] + (http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions).*/ + pending(); + } + + var fileName = "de:invalid:path", + fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.ENCODING_ERR); + done(); + }; + // create:false, exclusive:false, invalid path + root.getFile(fileName, { + create : false + }, succeed.bind(null, done, 'root.getFile - Error unexpected callback, file should not exists: ' + fileName), fail); + }); + it("file.spec.23 DirectoryEntry.getDirectory: get Entry for directory that does not exist", function (done) { + var dirName = "de.no.dir", + fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }; + // create:false, exclusive:false, directory does not exist + root.getDirectory(dirName, { + create : false + }, succeed.bind(null, done, 'root.getDirectory - Error unexpected callback, directory should not exists: ' + dirName), fail); + }); + it("file.spec.24 DirectoryEntry.getDirectory: create new dir with space then resolveLocalFileSystemURL", function (done) { + var dirName = "de create dir"; + + function win(directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(dirName); + expect(directory.fullPath).toCanonicallyMatch(joinURL(root.fullPath, dirName)); + // cleanup + deleteEntry(directory.name, done); + } + + function getDir(dirEntry) { + expect(dirEntry.filesystem).toBeDefined(); + expect(dirEntry.filesystem).toBe(root.filesystem); + var dirURI = dirEntry.toURL(); + // now encode URI and try to resolve + window.resolveLocalFileSystemURL(dirURI, win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - getDir function - Error resolving directory: ' + dirURI)); + } + + // create:true, exclusive:false, directory does not exist + root.getDirectory(dirName, { + create : true + }, getDir, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + // This test is excluded, and should probably be removed. Filesystem + // should always be properly encoded URLs, and *not* raw paths, and it + // doesn't make sense to double-encode the URLs and expect that to be + // handled by the implementation. + // If a particular platform uses paths internally rather than URLs, // then that platform should careful to pass them correctly to its + // backend. + xit("file.spec.25 DirectoryEntry.getDirectory: create new dir with space resolveLocalFileSystemURL with encoded URI", function (done) { + var dirName = "de create dir2", + dirPath = joinURL(root.fullPath, dirName); + + function win(directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(dirName); + expect(directory.fullPath).toCanonicallyMatch(dirPath); + // cleanup + deleteEntry(directory.name, done); + } + + function getDir(dirEntry) { + var dirURI = dirEntry.toURL(); + // now encode URI and try to resolve + window.resolveLocalFileSystemURL(encodeURI(dirURI), win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - getDir function - Error resolving directory: ' + dirURI)); + } + + // create:true, exclusive:false, directory does not exist + root.getDirectory(dirName, { + create : true + }, getDir, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.26 DirectoryEntry.getDirectory: create new directory", function (done) { + var dirName = "de.create.dir", + dirPath = joinURL(root.fullPath, dirName), + win = function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(dirName); + expect(directory.fullPath).toCanonicallyMatch(dirPath); + expect(directory.filesystem).toBeDefined(); + expect(directory.filesystem).toBe(root.filesystem); + // cleanup + deleteEntry(directory.name, done); + }; + // create:true, exclusive:false, directory does not exist + root.getDirectory(dirName, { + create : true + }, win, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.27 DirectoryEntry.getDirectory: create new directory (exclusive)", function (done) { + var dirName = "de.create.exclusive.dir", + dirPath = joinURL(root.fullPath, dirName), + win = function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(dirName); + expect(directory.fullPath).toCanonicallyMatch(dirPath); + expect(directory.filesystem).toBeDefined(); + expect(directory.filesystem).toBe(root.filesystem); + // cleanup + deleteEntry(directory.name, done); + }; + // create:true, exclusive:true, directory does not exist + root.getDirectory(dirName, { + create : true, + exclusive : true + }, win, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.28 DirectoryEntry.getDirectory: create directory that already exists", function (done) { + var dirName = "de.create.existing.dir", + dirPath = joinURL(root.fullPath, dirName), + win = function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(dirName); + expect(directory.fullPath).toCanonicallyMatch(dirPath); + // cleanup + deleteEntry(directory.name, done); + }; + // create directory to kick off it + root.getDirectory(dirName, { + create : true + }, function () { + root.getDirectory(dirName, { + create : true + }, win, failed.bind(null, done, 'root.getDirectory - Error creating existent second directory : ' + dirName)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.29 DirectoryEntry.getDirectory: create directory that already exists (exclusive)", function (done) { + + var dirName = "de.create.exclusive.existing.dir", + existingDir, + fail = function (error) { + expect(error).toBeDefined(); + if (isChrome) { + /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of PATH_EXISTS_ERR(code: 12) + on trying to exclusively create a file or directory, which already exists (Chrome).*/ + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + } else { + expect(error).toBeFileError(FileError.PATH_EXISTS_ERR); + } + // cleanup + deleteEntry(existingDir.name, done); + }; + // create directory to kick off it + root.getDirectory(dirName, { + create : true + }, function (directory) { + existingDir = directory; + // create:true, exclusive:true, directory exists + root.getDirectory(dirName, { + create : true, + exclusive : true + }, failed.bind(null, done, 'root.getDirectory - Unexpected success callback, second directory should not be created : ' + dirName), fail); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.30 DirectoryEntry.getDirectory: get Entry for existing directory", function (done) { + var dirName = "de.get.dir", + dirPath = joinURL(root.fullPath, dirName), + win = function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(dirName); + expect(directory.fullPath).toCanonicallyMatch(dirPath); + // cleanup + deleteEntry(directory.name, done); + }; + // create directory to kick it off + root.getDirectory(dirName, { + create : true + }, function () { + root.getDirectory(dirName, { + create : false + }, win, failed.bind(null, done, 'root.getDirectory - Error getting directory entry : ' + dirName)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.31 DirectoryEntry.getDirectory: get DirectoryEntry for invalid path", function (done) { + if (isBrowser) { + /*The plugin does not follow to ["8.3 Naming restrictions"] + (http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions).*/ + pending(); + } + + var dirName = "de:invalid:path", + fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.ENCODING_ERR); + done(); + }; + // create:false, exclusive:false, invalid path + root.getDirectory(dirName, { + create : false + }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, directory should not exists: ' + dirName), fail); + }); + it("file.spec.32 DirectoryEntry.getDirectory: get DirectoryEntry for existing file", function (done) { + var fileName = "de.existing.file", + existingFile, + fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.TYPE_MISMATCH_ERR); + // cleanup + deleteEntry(existingFile.name, done); + }; + // create file to kick off it + root.getFile(fileName, { + create : true + }, function (file) { + existingFile = file; + root.getDirectory(fileName, { + create : false + }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, directory should not exists: ' + fileName), fail); + }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName)); + }); + it("file.spec.33 DirectoryEntry.getFile: get FileEntry for existing directory", function (done) { + var dirName = "de.existing.dir", + existingDir, + fail = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.TYPE_MISMATCH_ERR); + // cleanup + deleteEntry(existingDir.name, done); + }; + // create directory to kick off it + root.getDirectory(dirName, { + create : true + }, function (directory) { + existingDir = directory; + root.getFile(dirName, { + create : false + }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, file should not exists: ' + dirName), fail); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.34 DirectoryEntry.removeRecursively on directory", function (done) { + var dirName = "de.removeRecursively", + subDirName = "dir", + dirExists = function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }; + // create a new directory entry to kick off it + root.getDirectory(dirName, { + create : true + }, function (entry) { + entry.getDirectory(subDirName, { + create : true + }, function (dir) { + entry.removeRecursively(function () { + root.getDirectory(dirName, { + create : false + }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, directory should not exists: ' + dirName), dirExists); + }, failed.bind(null, done, 'entry.removeRecursively - Error removing directory recursively : ' + dirName)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + subDirName)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.35 createReader: create reader on existing directory", function () { + // create reader for root directory + var reader = root.createReader(); + expect(reader).toBeDefined(); + expect(typeof reader.readEntries).toBe('function'); + }); + it("file.spec.36 removeRecursively on root file system", function (done) { + + var remove = function (error) { + expect(error).toBeDefined(); + if (isChrome) { + /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of + NO_MODIFICATION_ALLOWED_ERR(code: 6) on trying to call removeRecursively + on the root file system (Chrome).*/ + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + } else { + expect(error).toBeFileError(FileError.NO_MODIFICATION_ALLOWED_ERR); + } + done(); + }; + // remove root file system + root.removeRecursively(succeed.bind(null, done, 'root.removeRecursively - Unexpected success callback, root cannot be removed'), remove); + }); + }); + describe('DirectoryReader interface', function () { + describe("readEntries", function () { + it("file.spec.37 should read contents of existing directory", function (done) { + var reader, + win = function (entries) { + expect(entries).toBeDefined(); + expect(entries instanceof Array).toBe(true); + done(); + }; + // create reader for root directory + reader = root.createReader(); + // read entries + reader.readEntries(win, failed.bind(null, done, 'reader.readEntries - Error reading entries')); + }); + it("file.spec.37.1 should read contents of existing directory", function (done) { + var dirName = 'readEntries.dir', + fileName = 'readeEntries.file'; + root.getDirectory(dirName, { + create : true + }, function (directory) { + directory.getFile(fileName, { + create : true + }, function (fileEntry) { + var reader = directory.createReader(); + reader.readEntries(function (entries) { + expect(entries).toBeDefined(); + expect(entries instanceof Array).toBe(true); + expect(entries.length).toBe(1); + expect(entries[0].fullPath).toCanonicallyMatch(fileEntry.fullPath); + expect(entries[0].filesystem).not.toBe(null); + if (isChrome) { + // Slicing '[object {type}]' -> '{type}' + expect(entries[0].filesystem.toString().slice(8, -1)).toEqual("DOMFileSystem"); + } + else { + expect(entries[0].filesystem instanceof FileSystem).toBe(true); + } + + // cleanup + deleteEntry(directory.name, done); + }, failed.bind(null, done, 'reader.readEntries - Error reading entries from directory: ' + dirName)); + }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + fileName)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.109 should return an empty entry list on the second call", function (done) { + var reader, + fileName = 'test109.txt'; + // Add a file to ensure the root directory is non-empty and then read the contents of the directory. + root.getFile(fileName, { + create : true + }, function (entry) { + reader = root.createReader(); + //First read + reader.readEntries(function (entries) { + expect(entries).toBeDefined(); + expect(entries instanceof Array).toBe(true); + expect(entries.length).not.toBe(0); + //Second read + reader.readEntries(function (entries_) { + expect(entries_).toBeDefined(); + expect(entries_ instanceof Array).toBe(true); + expect(entries_.length).toBe(0); + //Clean up + deleteEntry(entry.name, done); + }, failed.bind(null, done, 'reader.readEntries - Error during SECOND reading of entries from [root] directory')); + }, failed.bind(null, done, 'reader.readEntries - Error during FIRST reading of entries from [root] directory')); + }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName)); + }); + }); + it("file.spec.38 should read contents of directory that has been removed", function (done) { + var dirName = "de.createReader.notfound"; + // create a new directory entry to kick off it + root.getDirectory(dirName, { + create : true + }, function (directory) { + directory.removeRecursively(function () { + var reader = directory.createReader(); + reader.readEntries(succeed.bind(null, done, 'reader.readEntries - Unexpected success callback, it should not read entries from deleted dir: ' + dirName), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + root.getDirectory(dirName, { + create : false + }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, it should not get deleted directory: ' + dirName), function (err) { + expect(err).toBeDefined(); + expect(err).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }); + }); + }, failed.bind(null, done, 'directory.removeRecursively - Error removing directory recursively : ' + dirName)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + }); + //DirectoryReader interface + describe('File', function () { + it("file.spec.39 constructor should be defined", function () { + expect(File).toBeDefined(); + expect(typeof File).toBe('function'); + }); + it("file.spec.40 should be define File attributes", function () { + var file = new File(); + expect(file.name).toBeDefined(); + expect(file.type).toBeDefined(); + expect(file.lastModifiedDate).toBeDefined(); + expect(file.size).toBeDefined(); + }); + }); + //File + describe('FileEntry', function () { + + it("file.spec.41 should be define FileEntry methods", function (done) { + var fileName = "fe.methods", + testFileEntry = function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(typeof fileEntry.createWriter).toBe('function'); + expect(typeof fileEntry.file).toBe('function'); + // cleanup + deleteEntry(fileEntry.name, done); + }; + // create a new file entry to kick off it + root.getFile(fileName, { + create : true + }, testFileEntry, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName)); + }); + it("file.spec.42 createWriter should return a FileWriter object", function (done) { + var fileName = "fe.createWriter", + testFile, + testWriter = function (writer) { + expect(writer).toBeDefined(); + if (isChrome) { + // Slicing '[object {type}]' -> '{type}' + expect(writer.toString().slice(8, -1)).toEqual("FileWriter"); + } + else { + expect(writer instanceof FileWriter).toBe(true); + } + + // cleanup + deleteEntry(testFile.name, done); + }; + // create a new file entry to kick off it + root.getFile(fileName, { + create : true + }, function (fileEntry) { + testFile = fileEntry; + fileEntry.createWriter(testWriter, failed.bind(null, done, 'fileEntry.createWriter - Error creating Writer from entry')); + }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName)); + }); + it("file.spec.43 file should return a File object", function (done) { + var fileName = "fe.file", + newFile, + testFile = function (file) { + expect(file).toBeDefined(); + if (isChrome) { + // Slicing '[object {type}]' -> '{type}' + expect(file.toString().slice(8, -1)).toEqual("File"); + } + else { + expect(file instanceof File).toBe(true); + } + + // cleanup + deleteEntry(newFile.name, done); + }; + // create a new file entry to kick off it + root.getFile(fileName, { + create : true + }, function (fileEntry) { + newFile = fileEntry; + fileEntry.file(testFile, failed.bind(null, done, 'fileEntry.file - Error reading file using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName)); + }); + it("file.spec.44 file: on File that has been removed", function (done) { + var fileName = "fe.no.file"; + // create a new file entry to kick off it + root.getFile(fileName, { + create : true + }, function (fileEntry) { + fileEntry.remove(function () { + fileEntry.file(succeed.bind(null, done, 'fileEntry.file - Unexpected success callback, file it should not be created from removed entry'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }); + }, failed.bind(null, done, 'fileEntry.remove - Error removing entry : ' + fileName)); + }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName)); + }); + }); + //FileEntry + describe('Entry', function () { + it("file.spec.45 Entry object", function (done) { + var fileName = "entry", + fullPath = joinURL(root.fullPath, fileName), + winEntry = function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(fileName); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + expect(typeof entry.getMetadata).toBe('function'); + expect(typeof entry.setMetadata).toBe('function'); + expect(typeof entry.moveTo).toBe('function'); + expect(typeof entry.copyTo).toBe('function'); + expect(typeof entry.toURL).toBe('function'); + expect(typeof entry.remove).toBe('function'); + expect(typeof entry.getParent).toBe('function'); + expect(typeof entry.createWriter).toBe('function'); + expect(typeof entry.file).toBe('function'); + // Clean up + deleteEntry(fileName, done); + }; + // create a new file entry + createFile(fileName, winEntry, failed.bind(null, done, 'createFile - Error creating file : ' + fileName)); + }); + it("file.spec.46 Entry.getMetadata on file", function (done) { + var fileName = "entry.metadata.file"; + // create a new file entry + createFile(fileName, function (entry) { + entry.getMetadata(function (metadata) { + expect(metadata).toBeDefined(); + expect(metadata.modificationTime instanceof Date).toBe(true); + expect(typeof metadata.size).toBe("number"); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'entry.getMetadata - Error getting metadata from entry : ' + fileName)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + fileName)); + }); + it("file.spec.47 Entry.getMetadata on directory", function (done) { + if (isIndexedDBShim) { + /* Does not support metadata for directories (Firefox, IE) */ + pending(); + } + + var dirName = "entry.metadata.dir"; + // create a new directory entry + createDirectory(dirName, function (entry) { + entry.getMetadata(function (metadata) { + expect(metadata).toBeDefined(); + expect(metadata.modificationTime instanceof Date).toBe(true); + expect(typeof metadata.size).toBe("number"); + expect(metadata.size).toBe(0); + // cleanup + deleteEntry(dirName, done); + }, failed.bind(null, done, 'entry.getMetadata - Error getting metadata from entry : ' + dirName)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.48 Entry.getParent on file in root file system", function (done) { + var fileName = "entry.parent.file", + rootPath = root.fullPath; + // create a new file entry + createFile(fileName, function (entry) { + entry.getParent(function (parent) { + expect(parent).toBeDefined(); + expect(parent.fullPath).toCanonicallyMatch(rootPath); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'entry.getParent - Error getting parent directory of file : ' + fileName)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + fileName)); + }); + it("file.spec.49 Entry.getParent on directory in root file system", function (done) { + var dirName = "entry.parent.dir", + rootPath = root.fullPath; + // create a new directory entry + createDirectory(dirName, function (entry) { + entry.getParent(function (parent) { + expect(parent).toBeDefined(); + expect(parent.fullPath).toCanonicallyMatch(rootPath); + // cleanup + deleteEntry(dirName, done); + }, failed.bind(null, done, 'entry.getParent - Error getting parent directory of directory : ' + dirName)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.50 Entry.getParent on root file system", function (done) { + var rootPath = root.fullPath, + winParent = function (parent) { + expect(parent).toBeDefined(); + expect(parent.fullPath).toCanonicallyMatch(rootPath); + done(); + }; + // create a new directory entry + root.getParent(winParent, failed.bind(null, done, 'root.getParent - Error getting parent directory of root')); + }); + it("file.spec.51 Entry.toURL on file", function (done) { + var fileName = "entry.uri.file", + rootPath = root.fullPath, + winURI = function (entry) { + var uri = entry.toURL(); + expect(uri).toBeDefined(); + expect(uri.indexOf(rootPath)).not.toBe(-1); + // cleanup + deleteEntry(fileName, done); + }; + // create a new file entry + createFile(fileName, winURI, failed.bind(null, done, 'createFile - Error creating file : ' + fileName)); + }); + it("file.spec.52 Entry.toURL on directory", function (done) { + var dirName_1 = "num 1", + dirName_2 = "num 2", + rootPath = root.fullPath; + createDirectory(dirName_1, function (entry) { + entry.getDirectory(dirName_2, { + create : true + }, function (entryFile) { + var uri = entryFile.toURL(); + expect(uri).toBeDefined(); + expect(uri).toContain('/num%201/num%202/'); + expect(uri.indexOf(rootPath)).not.toBe(-1); + // cleanup + deleteEntry(dirName_1, done); + }, failed.bind(null, done, 'entry.getDirectory - Error creating directory : ' + dirName_2)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName_1)); + }); + it("file.spec.53 Entry.remove on file", function (done) { + var fileName = "entr .rm.file"; + // create a new file entry + createFile(fileName, function (entry) { + expect(entry).toBeDefined(); + entry.remove(function () { + root.getFile(fileName, null, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get deleted file : ' + fileName), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(fileName, done); + }); + }, failed.bind(null, done, 'entry.remove - Error removing entry : ' + fileName)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + fileName)); + }); + it("file.spec.53.1 Entry.remove on filename with #s", function (done) { + var fileName = "entry.#rm#.file"; + // create a new file entry + createFile(fileName, function (entry) { + expect(entry).toBeDefined(); + entry.remove(function () { + root.getFile(fileName, null, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get deleted file : ' + fileName), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(fileName, done); + }); + }, failed.bind(null, done, 'entry.remove - Error removing entry : ' + fileName)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + fileName)); + }); + it("file.spec.54 remove on empty directory", function (done) { + var dirName = "entry.rm.dir"; + // create a new directory entry + createDirectory(dirName, function (entry) { + expect(entry).toBeDefined(); + entry.remove(function () { + root.getDirectory(dirName, null, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, it should not get deleted directory : ' + dirName), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(dirName, done); + }); + }, failed.bind(null, done, 'entry.remove - Error removing entry : ' + dirName)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.55 remove on non-empty directory", function (done) { + if (isIndexedDBShim) { + /* Both Entry.remove and directoryEntry.removeRecursively don't fail when removing + non-empty directories - directories being removed are cleaned + along with contents instead (Firefox, IE)*/ + pending(); + } + + var dirName = "ent y.rm.dir.not.empty", + fileName = "re ove.txt", + fullPath = joinURL(root.fullPath, dirName); + // create a new directory entry + createDirectory(dirName, function (entry) { + entry.getFile(fileName, { + create : true + }, function (fileEntry) { + entry.remove(succeed.bind(null, done, 'entry.remove - Unexpected success callback, it should not remove a directory that contains files : ' + dirName), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + root.getDirectory(dirName, null, function (entry) { + expect(entry).toBeDefined(); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + // cleanup + deleteEntry(dirName, done); + }, failed.bind(null, done, 'root.getDirectory - Error getting directory : ' + dirName)); + }); + }, failed.bind(null, done, 'entry.getFile - Error creating file : ' + fileName + ' inside of ' + dirName)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName)); + }); + it("file.spec.56 remove on root file system", function (done) { + + // remove entry that doesn't exist + root.remove(succeed.bind(null, done, 'entry.remove - Unexpected success callback, it should not remove entry that it does not exists'), function (error) { + expect(error).toBeDefined(); + if (isChrome) { + /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of + NO_MODIFICATION_ALLOWED_ERR(code: 6) on trying to call removeRecursively + on the root file system.*/ + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + } else { + expect(error).toBeFileError(FileError.NO_MODIFICATION_ALLOWED_ERR); + } + done(); + }); + }); + it("file.spec.57 copyTo: file", function (done) { + var file1 = "entry copy.file1", + file2 = "entry copy.file2", + fullPath = joinURL(root.fullPath, file2); + // create a new file entry to kick off it + deleteEntry(file2, function () { + createFile(file1, function (fileEntry) { + // copy file1 to file2 + fileEntry.copyTo(root, file2, function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + expect(entry.name).toCanonicallyMatch(file2); + root.getFile(file2, { + create : false + }, function (entry2) { + expect(entry2).toBeDefined(); + expect(entry2.isFile).toBe(true); + expect(entry2.isDirectory).toBe(false); + expect(entry2.fullPath).toCanonicallyMatch(fullPath); + expect(entry2.name).toCanonicallyMatch(file2); + // cleanup + deleteEntry(file1, function () { + deleteEntry(file2, done); + }); + }, failed.bind(null, done, 'root.getFile - Error getting copied file : ' + file2)); + }, failed.bind(null, done, 'fileEntry.copyTo - Error copying file : ' + file2)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'deleteEntry - Error removing file : ' + file2)); + }); + it("file.spec.58 copyTo: file onto itself", function (done) { + var file1 = "entry.copy.fos.file1"; + // create a new file entry to kick off it + createFile(file1, function (entry) { + // copy file1 onto itself + entry.copyTo(root, null, succeed.bind(null, done, 'entry.copyTo - Unexpected success callback, it should not copy a null file'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + // cleanup + deleteEntry(file1, done); + }); + }, failed.bind(null, done, 'createFile - Error creating file : ' + file1)); + }); + it("file.spec.59 copyTo: directory", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "file1", + srcDir = "entry.copy.srcDir", + dstDir = "entry.copy.dstDir", + dstPath = joinURL(root.fullPath, dstDir), + filePath = joinURL(dstPath, file1); + // create a new directory entry to kick off it + deleteEntry(dstDir, function () { + createDirectory(srcDir, function (directory) { + // create a file within new directory + directory.getFile(file1, { + create : true + }, function () { + directory.copyTo(root, dstDir, function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.fullPath).toCanonicallyMatch(dstPath); + expect(directory.name).toCanonicallyMatch(dstDir); + root.getDirectory(dstDir, { + create : false + }, function (dirEntry) { + expect(dirEntry).toBeDefined(); + expect(dirEntry.isFile).toBe(false); + expect(dirEntry.isDirectory).toBe(true); + expect(dirEntry.fullPath).toCanonicallyMatch(dstPath); + expect(dirEntry.name).toCanonicallyMatch(dstDir); + dirEntry.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.isFile).toBe(true); + expect(fileEntry.isDirectory).toBe(false); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + expect(fileEntry.name).toCanonicallyMatch(file1); + // cleanup + deleteEntry(srcDir, function () { + deleteEntry(dstDir, done); + }); + }, failed.bind(null, done, 'dirEntry.getFile - Error getting file : ' + file1)); + }, failed.bind(null, done, 'root.getDirectory - Error getting copied directory : ' + dstDir)); + }, failed.bind(null, done, 'directory.copyTo - Error copying directory : ' + srcDir + ' to :' + dstDir)); + }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }); + it("file.spec.60 copyTo: directory to backup at same root directory", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "file1", + srcDir = "entry.copy srcDirSame", + dstDir = "entry.copy srcDirSame-backup", + dstPath = joinURL(root.fullPath, dstDir), + filePath = joinURL(dstPath, file1); + // create a new directory entry to kick off it + deleteEntry(dstDir, function () { + createDirectory(srcDir, function (directory) { + directory.getFile(file1, { + create : true + }, function () { + directory.copyTo(root, dstDir, function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.fullPath).toCanonicallyMatch(dstPath); + expect(directory.name).toCanonicallyMatch(dstDir); + root.getDirectory(dstDir, { + create : false + }, function (dirEntry) { + expect(dirEntry).toBeDefined(); + expect(dirEntry.isFile).toBe(false); + expect(dirEntry.isDirectory).toBe(true); + expect(dirEntry.fullPath).toCanonicallyMatch(dstPath); + expect(dirEntry.name).toCanonicallyMatch(dstDir); + dirEntry.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.isFile).toBe(true); + expect(fileEntry.isDirectory).toBe(false); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + expect(fileEntry.name).toCanonicallyMatch(file1); + // cleanup + deleteEntry(srcDir, function () { + deleteEntry(dstDir, done); + }); + }, failed.bind(null, done, 'dirEntry.getFile - Error getting file : ' + file1)); + }, failed.bind(null, done, 'root.getDirectory - Error getting copied directory : ' + dstDir)); + }, failed.bind(null, done, 'directory.copyTo - Error copying directory : ' + srcDir + ' to :' + dstDir)); + }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }); + it("file.spec.61 copyTo: directory onto itself", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "file1", + srcDir = "entry.copy.dos.srcDir", + srcPath = joinURL(root.fullPath, srcDir), + filePath = joinURL(srcPath, file1); + // create a new directory entry to kick off it + createDirectory(srcDir, function (directory) { + // create a file within new directory + directory.getFile(file1, { + create : true + }, function (fileEntry) { + // copy srcDir onto itself + directory.copyTo(root, null, succeed.bind(null, done, 'directory.copyTo - Unexpected success callback, it should not copy file: ' + srcDir + ' to a null destination'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + root.getDirectory(srcDir, { + create : false + }, function (dirEntry) { + expect(dirEntry).toBeDefined(); + expect(dirEntry.fullPath).toCanonicallyMatch(srcPath); + dirEntry.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(srcDir, done); + }, failed.bind(null, done, 'dirEntry.getFile - Error getting file : ' + file1)); + }, failed.bind(null, done, 'root.getDirectory - Error getting directory : ' + srcDir)); + }); + }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }); + it("file.spec.62 copyTo: directory into itself", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var srcDir = "entry.copy.dis.srcDir", + dstDir = "entry.copy.dis.dstDir", + srcPath = joinURL(root.fullPath, srcDir); + // create a new directory entry to kick off it + createDirectory(srcDir, function (directory) { + // copy source directory into itself + directory.copyTo(directory, dstDir, succeed.bind(null, done, 'directory.copyTo - Unexpected success callback, it should not copy a directory ' + srcDir + ' into itself'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + root.getDirectory(srcDir, { + create : false + }, function (dirEntry) { + // returning confirms existence so just check fullPath entry + expect(dirEntry).toBeDefined(); + expect(dirEntry.fullPath).toCanonicallyMatch(srcPath); + // cleanup + deleteEntry(srcDir, done); + }, failed.bind(null, done, 'root.getDirectory - Error getting directory : ' + srcDir)); + }); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }); + it("file.spec.63 copyTo: directory that does not exist", function (done) { + var file1 = "entry.copy.dnf.file1", + dirName = 'dir-foo'; + createFile(file1, function (fileEntry) { + createDirectory(dirName, function (dirEntry) { + dirEntry.remove(function () { + fileEntry.copyTo(dirEntry, null, succeed.bind(null, done, 'fileEntry.copyTo - Unexpected success callback, it should not copy a file ' + file1 + ' into a removed directory'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }); + }, failed.bind(null, done, 'dirEntry.remove - Error removing directory : ' + dirName)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + file1)); + }); + it("file.spec.64 copyTo: invalid target name", function (done) { + if (isBrowser) { + /*The plugin does not follow ["8.3 Naming restrictions"] + (http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions*/ + pending(); + } + + var file1 = "entry.copy.itn.file1", + file2 = "bad:file:name"; + // create a new file entry + createFile(file1, function (entry) { + // copy file1 to file2 + entry.copyTo(root, file2, succeed.bind(null, done, 'entry.copyTo - Unexpected success callback, it should not copy a file ' + file1 + ' to an invalid file name: ' + file2), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.ENCODING_ERR); + // cleanup + deleteEntry(file1, done); + }); + }, failed.bind(null, done, 'createFile - Error creating file : ' + file1)); + }); + it("file.spec.65 moveTo: file to same parent", function (done) { + var file1 = "entry.move.fsp.file1", + file2 = "entry.move.fsp.file2", + dstPath = joinURL(root.fullPath, file2); + // create a new file entry to kick off it + createFile(file1, function (entry) { + // move file1 to file2 + entry.moveTo(root, file2, function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.fullPath).toCanonicallyMatch(dstPath); + expect(entry.name).toCanonicallyMatch(file2); + root.getFile(file2, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(dstPath); + root.getFile(file1, { + create : false + }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) { + //expect(navigator.fileMgr.testFileExists(srcPath) === false, "original file should not exist."); + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(file1, function () { + deleteEntry(file2, done); + }); + }); + }, failed.bind(null, done, 'root.getFile - Error getting file : ' + file2)); + }, failed.bind(null, done, 'entry.moveTo - Error moving file : ' + file1 + ' to root as: ' + file2)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + file1)); + }); + it("file.spec.66 moveTo: file to new parent", function (done) { + var file1 = "entry.move.fnp.file1", + dir = "entry.move.fnp.dir", + dstPath = joinURL(joinURL(root.fullPath, dir), file1); + // ensure destination directory is cleaned up first + deleteEntry(dir, function () { + // create a new file entry to kick off it + createFile(file1, function (entry) { + // create a parent directory to move file to + root.getDirectory(dir, { + create : true + }, function (directory) { + // move file1 to new directory + // move the file + entry.moveTo(directory, null, function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.fullPath).toCanonicallyMatch(dstPath); + expect(entry.name).toCanonicallyMatch(file1); + // test the moved file exists + directory.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(dstPath); + root.getFile(file1, { + create : false + }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(file1, function () { + deleteEntry(dir, done); + }); + }); + }, failed.bind(null, done, 'directory.getFile - Error getting file : ' + file1 + ' from: ' + dir)); + }, failed.bind(null, done, 'entry.moveTo - Error moving file : ' + file1 + ' to: ' + dir + ' with the same name')); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dir)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dir)); + }); + it("file.spec.67 moveTo: directory to same parent", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "file1", + srcDir = "entry.move.dsp.srcDir", + dstDir = "entry.move.dsp.dstDir", + dstPath = joinURL(root.fullPath, dstDir), + filePath = joinURL(dstPath, file1); + // ensure destination directory is cleaned up before it + deleteEntry(dstDir, function () { + // create a new directory entry to kick off it + createDirectory(srcDir, function (directory) { + // create a file within directory + directory.getFile(file1, { + create : true + }, function () { + // move srcDir to dstDir + directory.moveTo(root, dstDir, function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.fullPath).toCanonicallyMatch(dstPath); + expect(directory.name).toCanonicallyMatch(dstDir); + // test that moved file exists in destination dir + directory.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // check that the moved file no longer exists in original dir + root.getFile(file1, { + create : false + }, succeed.bind(null, done, 'directory.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(srcDir, function() { + deleteEntry(dstDir, done); + }); + }); + }, failed.bind(null, done, 'directory.getFile - Error getting file : ' + file1 + ' from: ' + srcDir)); + }, failed.bind(null, done, 'entry.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir)); + }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }); + it("file.spec.68 moveTo: directory to same parent with same name", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "file1", + srcDir = "entry.move.dsp.srcDir", + dstDir = "entry.move.dsp.srcDir-backup", + dstPath = joinURL(root.fullPath, dstDir), + filePath = joinURL(dstPath, file1); + // ensure destination directory is cleaned up before it + deleteEntry(dstDir, function () { + // create a new directory entry to kick off it + createDirectory(srcDir, function (directory) { + // create a file within directory + directory.getFile(file1, { + create : true + }, function () { + // move srcDir to dstDir + directory.moveTo(root, dstDir, function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.fullPath).toCanonicallyMatch(dstPath); + expect(directory.name).toCanonicallyMatch(dstDir); + // check that moved file exists in destination dir + directory.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // check that the moved file no longer exists in original dir + root.getFile(file1, { + create : false + }, succeed.bind(null, done, 'directory.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(srcDir, function() { + deleteEntry(dstDir, done); + }); + }); + }, failed.bind(null, done, 'directory.getFile - Error getting file : ' + file1 + ' from: ' + srcDir)); + }, failed.bind(null, done, 'entry.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir)); + }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }); + it("file.spec.69 moveTo: directory to new parent", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "file1", + srcDir = "entry.move.dnp.srcDir", + dstDir = "entry.move.dnp.dstDir", + dstPath = joinURL(root.fullPath, dstDir), + filePath = joinURL(dstPath, file1); + // ensure destination directory is cleaned up before it + deleteEntry(dstDir, function () { + // create a new directory entry to kick off it + createDirectory(srcDir, function (directory) { + // create a file within directory + directory.getFile(file1, { + create : true + }, function () { + // move srcDir to dstDir + directory.moveTo(root, dstDir, function (dirEntry) { + expect(dirEntry).toBeDefined(); + expect(dirEntry.isFile).toBe(false); + expect(dirEntry.isDirectory).toBe(true); + expect(dirEntry.fullPath).toCanonicallyMatch(dstPath); + expect(dirEntry.name).toCanonicallyMatch(dstDir); + // test that moved file exists in destination dir + dirEntry.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // test that the moved file no longer exists in original dir + root.getFile(file1, { + create : false + }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(srcDir, function() { + deleteEntry(dstDir, done); + }); + }); + }, failed.bind(null, done, 'directory.getFile - Error getting file : ' + file1 + ' from: ' + dstDir)); + }, failed.bind(null, done, 'directory.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir)); + }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }); + + it("file.spec.131 moveTo: directories tree to new parent", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var srcDir = "entry.move.dnp.srcDir"; + var srcDirNestedFirst = "entry.move.dnp.srcDir.Nested1"; + var srcDirNestedSecond = "entry.move.dnp.srcDir.Nested2"; + var dstDir = "entry.move.dnp.dstDir"; + + createDirectory(dstDir, function (dstDirectory) { + createDirectory(srcDir, function (srcDirectory) { + srcDirectory.getDirectory(srcDirNestedFirst, { create: true }, function () { + srcDirectory.getDirectory(srcDirNestedSecond, { create: true }, function () { + srcDirectory.moveTo(dstDirectory, srcDir, function successMove(transferredDirectory) { + var directoryReader = transferredDirectory.createReader(); + directoryReader.readEntries(function successRead(entries) { + expect(entries.length).toBe(2); + expect(entries[0].name).toBe(srcDirNestedFirst); + expect(entries[1].name).toBe(srcDirNestedSecond); + deleteEntry(dstDir, done); + }, failed.bind(null, done, 'Error getting entries from: ' + transferredDirectory)); + }, failed.bind(null, done, 'directory.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir)); + }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + srcDirNestedSecond)); + }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + srcDirNestedFirst)); + }, failed.bind(null, done, 'createDirectory - Error creating source directory : ' + srcDir)); + }, failed.bind(null, done, 'createDirectory - Error creating dest directory : ' + dstDir)); + }); + + it("file.spec.70 moveTo: directory onto itself", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "file1", + srcDir = "entry.move.dos.srcDir", + srcPath = joinURL(root.fullPath, srcDir), + filePath = joinURL(srcPath, file1); + // create a new directory entry to kick off it + createDirectory(srcDir, function (directory) { + // create a file within new directory + directory.getFile(file1, { + create : true + }, function () { + // move srcDir onto itself + directory.moveTo(root, null, succeed.bind(null, done, 'directory.moveTo - Unexpected success callback, it should not move directory to invalid path'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + // test that original dir still exists + root.getDirectory(srcDir, { + create : false + }, function (dirEntry) { + // returning confirms existence so just check fullPath entry + expect(dirEntry).toBeDefined(); + expect(dirEntry.fullPath).toCanonicallyMatch(srcPath); + dirEntry.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(srcDir, done); + }, failed.bind(null, done, 'dirEntry.getFile - Error getting file : ' + file1 + ' from: ' + srcDir)); + }, failed.bind(null, done, 'root.getDirectory - Error getting directory : ' + srcDir)); + }); + }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }); + it("file.spec.71 moveTo: directory into itself", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var srcDir = "entry.move.dis.srcDir", + dstDir = "entry.move.dis.dstDir", + srcPath = joinURL(root.fullPath, srcDir); + // create a new directory entry to kick off it + createDirectory(srcDir, function (directory) { + // move source directory into itself + directory.moveTo(directory, dstDir, succeed.bind(null, done, 'directory.moveTo - Unexpected success callback, it should not move a directory into itself: ' + srcDir), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + // make sure original directory still exists + root.getDirectory(srcDir, { + create : false + }, function (entry) { + expect(entry).toBeDefined(); + expect(entry.fullPath).toCanonicallyMatch(srcPath); + // cleanup + deleteEntry(srcDir, done); + }, failed.bind(null, done, 'root.getDirectory - Error getting directory, making sure that original directory still exists: ' + srcDir)); + }); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }); + it("file.spec.130 moveTo: directory into similar directory", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var srcDir = "entry.move.dis.srcDir", + dstDir = "entry.move.dis.srcDir-backup"; + // create a new directory entry to kick off it + createDirectory(srcDir, function (srcDirEntry) { + deleteEntry(dstDir, function () { + createDirectory(dstDir, function (dstDirEntry) { + // move source directory into itself + srcDirEntry.moveTo(dstDirEntry, 'file', function (newDirEntry) { + expect(newDirEntry).toBeDefined(); + deleteEntry(dstDir, done); + }, failed.bind(null, done, 'directory.moveTo - Error moving a directory into a similarly-named directory: ' + srcDir)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dstDir)); + }, failed.bind(null, done, 'deleteEntry - Error deleting directory : ' + dstDir)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }); + it("file.spec.72 moveTo: file onto itself", function (done) { + var file1 = "entry.move.fos.file1", + filePath = joinURL(root.fullPath, file1); + // create a new file entry to kick off it + createFile(file1, function (entry) { + // move file1 onto itself + entry.moveTo(root, null, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, it should not move a file: ' + file1 + ' into the same parent'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + //test that original file still exists + root.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(file1, done); + }, failed.bind(null, done, 'root.getFile - Error getting file, making sure that original file still exists: ' + file1)); + }); + }, failed.bind(null, done, 'createFile - Error creating file : ' + file1)); + }); + it("file.spec.73 moveTo: file onto existing directory", function (done) { + var file1 = "entry.move.fod.file1", + dstDir = "entry.move.fod.dstDir", + subDir = "subDir", + dirPath = joinURL(joinURL(root.fullPath, dstDir), subDir), + filePath = joinURL(root.fullPath, file1); + // ensure destination directory is cleaned up before it + deleteEntry(dstDir, function () { + // create a new file entry to kick off it + createFile(file1, function (entry) { + // create top level directory + root.getDirectory(dstDir, { + create : true + }, function (directory) { + // create sub-directory + directory.getDirectory(subDir, { + create : true + }, function (subDirectory) { + // move file1 onto sub-directory + entry.moveTo(directory, subDir, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, it should not move a file: ' + file1 + ' into directory: ' + dstDir + '\n' + subDir + ' directory already exists'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + // check that original dir still exists + directory.getDirectory(subDir, { + create : false + }, function (dirEntry) { + expect(dirEntry).toBeDefined(); + expect(dirEntry.fullPath).toCanonicallyMatch(dirPath); + // check that original file still exists + root.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(file1, function () { + deleteEntry(dstDir, done); + }); + }, failed.bind(null, done, 'root.getFile - Error getting file, making sure that original file still exists: ' + file1)); + }, failed.bind(null, done, 'directory.getDirectory - Error getting directory, making sure that original directory still exists: ' + subDir)); + }); + }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + subDir)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dstDir)); + }, failed.bind(null, done, 'createFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }); + it("file.spec.74 moveTo: directory onto existing file", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "entry.move.dof.file1", + srcDir = "entry.move.dof.srcDir", + dirPath = joinURL(root.fullPath, srcDir), + filePath = joinURL(root.fullPath, file1); + // create a new directory entry to kick off it + createDirectory(srcDir, function (entry) { + // create file + root.getFile(file1, { + create : true + }, function (fileEntry) { + // move directory onto file + entry.moveTo(root, file1, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, it should not move : \n' + srcDir + ' into root directory renamed as ' + file1 + '\n' + file1 + ' file already exists'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + // test that original directory exists + root.getDirectory(srcDir, { + create : false + }, function (dirEntry) { + // returning confirms existence so just check fullPath entry + expect(dirEntry).toBeDefined(); + expect(dirEntry.fullPath).toCanonicallyMatch(dirPath); + // test that original file exists + root.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(file1, function () { + deleteEntry(srcDir, done); + }); + }, failed.bind(null, done, 'root.getFile - Error getting file, making sure that original file still exists: ' + file1)); + }, failed.bind(null, done, 'directory.getDirectory - Error getting directory, making sure that original directory still exists: ' + srcDir)); + }); + }, failed.bind(null, done, 'root.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }); + it("file.spec.75 copyTo: directory onto existing file", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "entry.copy.dof.file1", + srcDir = "entry.copy.dof.srcDir", + dirPath = joinURL(root.fullPath, srcDir), + filePath = joinURL(root.fullPath, file1); + // create a new directory entry to kick off it + createDirectory(srcDir, function (entry) { + // create file + root.getFile(file1, { + create : true + }, function () { + // copy directory onto file + entry.copyTo(root, file1, succeed.bind(null, done, 'entry.copyTo - Unexpected success callback, it should not copy : \n' + srcDir + ' into root directory renamed as ' + file1 + '\n' + file1 + ' file already exists'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + //check that original dir still exists + root.getDirectory(srcDir, { + create : false + }, function (dirEntry) { + // returning confirms existence so just check fullPath entry + expect(dirEntry).toBeDefined(); + expect(dirEntry.fullPath).toCanonicallyMatch(dirPath); + // test that original file still exists + root.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // cleanup + deleteEntry(file1, function () { + deleteEntry(srcDir, done); + }); + }, failed.bind(null, done, 'root.getFile - Error getting file, making sure that original file still exists: ' + file1)); + }, failed.bind(null, done, 'root.getDirectory - Error getting directory, making sure that original directory still exists: ' + srcDir)); + }); + }, failed.bind(null, done, 'root.getFile - Error creating file : ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }); + it("file.spec.76 moveTo: directory onto directory that is not empty", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var srcDir = "entry.move.dod.srcDir", + dstDir = "entry.move.dod.dstDir", + subDir = "subDir", + srcPath = joinURL(root.fullPath, srcDir), + dstPath = joinURL(joinURL(root.fullPath, dstDir), subDir); + // ensure destination directory is cleaned up before it + deleteEntry(dstDir, function () { + // create a new file entry to kick off it + createDirectory(srcDir, function (entry) { + // create top level directory + root.getDirectory(dstDir, { + create : true + }, function (directory) { + // create sub-directory + directory.getDirectory(subDir, { + create : true + }, function () { + // move srcDir onto dstDir (not empty) + entry.moveTo(root, dstDir, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, it should not copy : \n' + srcDir + ' into root directory renamed as ' + dstDir + '\n' + dstDir + ' directory already exists'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + // making sure destination directory still exists + directory.getDirectory(subDir, { + create : false + }, function (dirEntry) { + // returning confirms existence so just check fullPath entry + expect(dirEntry).toBeDefined(); + expect(dirEntry.fullPath).toCanonicallyMatch(dstPath); + // making sure source directory exists + root.getDirectory(srcDir, { + create : false + }, function (srcEntry) { + expect(srcEntry).toBeDefined(); + expect(srcEntry.fullPath).toCanonicallyMatch(srcPath); + // cleanup + deleteEntry(srcDir, function () { + deleteEntry(dstDir, done); + }); + }, failed.bind(null, done, 'root.getDirectory - Error getting directory, making sure that original directory still exists: ' + srcDir)); + }, failed.bind(null, done, 'directory.getDirectory - Error getting directory, making sure that original directory still exists: ' + subDir)); + }); + }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + subDir)); + }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + subDir)); + }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }); + it("file.spec.77 moveTo: file replace existing file", function (done) { + var file1 = "entry.move.frf.file1", + file2 = "entry.move.frf.file2", + file2Path = joinURL(root.fullPath, file2); + // create a new directory entry to kick off it + createFile(file1, function (entry) { + // create file + root.getFile(file2, { + create : true + }, function () { + // replace file2 with file1 + entry.moveTo(root, file2, function (entry2) { + expect(entry2).toBeDefined(); + expect(entry2.isFile).toBe(true); + expect(entry2.isDirectory).toBe(false); + expect(entry2.fullPath).toCanonicallyMatch(file2Path); + expect(entry2.name).toCanonicallyMatch(file2); + // old file should not exists + root.getFile(file1, { + create : false + }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, file: ' + file1 + ' should not exists'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // test that new file exists + root.getFile(file2, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(file2Path); + // cleanup + deleteEntry(file1, function () { + deleteEntry(file2, done); + }); + }, failed.bind(null, done, 'root.getFile - Error getting moved file: ' + file2)); + }); + }, failed.bind(null, done, 'entry.moveTo - Error moving file : ' + file1 + ' to root as: ' + file2)); + }, failed.bind(null, done, 'root.getFile - Error creating file: ' + file2)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + file1)); + }); + it("file.spec.78 moveTo: directory replace empty directory", function (done) { + if (isIndexedDBShim) { + /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */ + pending(); + } + + var file1 = "file1", + srcDir = "entry.move.drd.srcDir", + dstDir = "entry.move.drd.dstDir", + dstPath = joinURL(root.fullPath, dstDir), + filePath = dstPath + '/' + file1; + // ensure destination directory is cleaned up before it + deleteEntry(dstDir, function () { + // create a new directory entry to kick off it + createDirectory(srcDir, function (directory) { + // create a file within source directory + directory.getFile(file1, { + create : true + }, function () { + // create destination directory + root.getDirectory(dstDir, { + create : true + }, function () { + // move srcDir to dstDir + directory.moveTo(root, dstDir, function (dirEntry) { + expect(dirEntry).toBeDefined(); + expect(dirEntry.isFile).toBe(false); + expect(dirEntry.isDirectory).toBe(true); + expect(dirEntry.fullPath).toCanonicallyMatch(dstPath); + expect(dirEntry.name).toCanonicallyMatch(dstDir); + // check that old directory contents have been moved + dirEntry.getFile(file1, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.fullPath).toCanonicallyMatch(filePath); + // check that old directory no longer exists + root.getDirectory(srcDir, { + create : false + }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, directory: ' + srcDir + ' should not exists'), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + // cleanup + deleteEntry(srcDir, function () { + deleteEntry(dstDir, done); + }); + }); + }, failed.bind(null, done, 'dirEntry.getFile - Error getting moved file: ' + file1)); + }, failed.bind(null, done, 'entry.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory: ' + dstDir)); + }, failed.bind(null, done, 'root.getFile - Error creating file: ' + file1)); + }, failed.bind(null, done, 'createDirectory - Error creating directory: ' + srcDir)); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }); + it("file.spec.79 moveTo: directory that does not exist", function (done) { + + var file1 = "entry.move.dnf.file1", + dstDir = "entry.move.dnf.dstDir", + dstPath = joinURL(root.fullPath, dstDir); + // create a new file entry to kick off it + createFile(file1, function (entry) { + // move file to directory that does not exist + var directory = new DirectoryEntry(); + directory.filesystem = root.filesystem; + directory.fullPath = dstPath; + entry.moveTo(directory, null, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, parent directory: ' + dstPath + ' should not exists'), function (error) { + expect(error).toBeDefined(); + if (isChrome) { + /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of NOT_FOUND_ERR(code: 1) + on trying to moveTo directory that does not exist.*/ + expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR); + } else { + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + } + // cleanup + deleteEntry(file1, done); + }); + }, failed.bind(null, done, 'createFile - Error creating file: ' + file1)); + }); + it("file.spec.80 moveTo: invalid target name", function (done) { + if (isBrowser) { + /*The plugin does not follow ["8.3 Naming restrictions"] + (http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions*/ + pending(); + } + + var file1 = "entry.move.itn.file1", + file2 = "bad:file:name"; + // create a new file entry to kick off it + createFile(file1, function (entry) { + // move file1 to file2 + entry.moveTo(root, file2, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, : ' + file1 + ' to root as: ' + file2), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.ENCODING_ERR); + // cleanup + deleteEntry(file1, done); + }); + }, failed.bind(null, done, 'createFile - Error creating file: ' + file1)); + }); + }); + //Entry + describe('FileReader', function () { + it("file.spec.81 should have correct methods", function () { + var reader = new FileReader(); + expect(reader).toBeDefined(); + expect(typeof reader.readAsBinaryString).toBe('function'); + expect(typeof reader.readAsDataURL).toBe('function'); + expect(typeof reader.readAsText).toBe('function'); + expect(typeof reader.readAsArrayBuffer).toBe('function'); + expect(typeof reader.abort).toBe('function'); + expect(reader.result).toBe(null); + }); + }); + //FileReader + describe('Read method', function () { + it("file.spec.82 should error out on non-existent file", function (done) { + var fileName = cordova.platformId === 'windowsphone' ? root.toURL() + "/" + "somefile.txt" : "somefile.txt", + verifier = function (evt) { + expect(evt).toBeDefined(); + expect(evt.target.error).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }; + root.getFile(fileName, { + create : true + }, function (entry) { + entry.file(function (file) { + deleteEntry(fileName, function () { + //Create FileReader + var reader = new FileReader(); + reader.onerror = verifier; + reader.onload = succeed.bind(null, done, 'reader.onload - Unexpected success callback, file: ' + fileName + ' it should not exists'); + reader.readAsText(file); + }, failed.bind(null, done, 'deleteEntry - Error removing file: ' + fileName)); + }, failed.bind(null, done, 'entry.file - Error reading file: ' + fileName)); + }, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName)); + }); + it("file.spec.83 should be able to read native blob objects", function (done) { + // Skip test if blobs are not supported (e.g.: Android 2.3). + if (typeof window.Blob == 'undefined' || typeof window.Uint8Array == 'undefined') { + expect(true).toFailWithMessage('Platform does not supported this feature'); + done(); + } + var contents = 'asdf'; + var uint8Array = new Uint8Array(contents.length); + for (var i = 0; i < contents.length; ++i) { + uint8Array[i] = contents.charCodeAt(i); + } + var Builder = window.BlobBuilder || window.WebKitBlobBuilder; + var blob; + if (Builder) { + var builder = new Builder(); + builder.append(uint8Array.buffer); + builder.append(contents); + blob = builder.getBlob("text/plain"); + } else { + try { + // iOS 6 does not support Views, so pass in the buffer. + blob = new Blob([uint8Array.buffer, contents]); + } catch (e) { + // Skip the test if we can't create a blob (e.g.: iOS 5). + if (e instanceof TypeError) { + expect(true).toFailWithMessage('Platform does not supported this feature'); + done(); + } + throw e; + } + } + var verifier = function (evt) { + expect(evt).toBeDefined(); + expect(evt.target.result).toBe('asdfasdf'); + done(); + }; + var reader = new FileReader(); + reader.onloadend = verifier; + reader.readAsText(blob); + }); + function writeDummyFile(writeBinary, callback, done, fileContents) { + var fileName = "dummy.txt", + fileEntry = null, + // use default string if file data is not provided + fileData = fileContents !== undefined ? fileContents : + '\u20AC\xEB - There is an exception to every rule. Except this one.', + fileDataAsBinaryString = fileContents !== undefined ? fileContents : + '\xe2\x82\xac\xc3\xab - There is an exception to every rule. Except this one.'; + + function createWriter(fe) { + fileEntry = fe; + fileEntry.createWriter(writeFile, failed.bind(null, done, 'fileEntry.createWriter - Error reading file: ' + fileName)); + } + + // writes file and reads it back in + function writeFile(writer) { + writer.onwriteend = function () { + fileEntry.file(function (f) { + callback(fileEntry, f, fileData, fileDataAsBinaryString); + }, failed.bind(null, done, 'writer.onwriteend - Error writing data on file: ' + fileName)); + }; + writer.write(fileData); + } + + fileData += writeBinary ? 'bin:\x01\x00' : ''; + fileDataAsBinaryString += writeBinary ? 'bin:\x01\x00' : ''; + // create a file, write to it, and read it in again + createFile(fileName, createWriter, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + } + function runReaderTest(funcName, writeBinary, done, progressFunc, verifierFunc, sliceStart, sliceEnd, fileContents) { + writeDummyFile(writeBinary, function (fileEntry, file, fileData, fileDataAsBinaryString) { + var verifier = function (evt) { + expect(evt).toBeDefined(); + verifierFunc(evt, fileData, fileDataAsBinaryString); + }; + var reader = new FileReader(); + reader.onprogress = progressFunc; + reader.onload = verifier; + reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + file + ' using function: ' + funcName); + if (sliceEnd !== undefined) { + // 'type' is specified so that is will be preserved in the resulting file: + // http://www.w3.org/TR/FileAPI/#slice-method-algo -> "6.4.1. The slice method" -> 4. A), 6. c) + file = file.slice(sliceStart, sliceEnd, file.type); + } else if (sliceStart !== undefined) { + file = file.slice(sliceStart, file.size, file.type); + } + reader[funcName](file); + }, done, fileContents); + } + function arrayBufferEqualsString(ab, str) { + var buf = new Uint8Array(ab); + var match = buf.length == str.length; + for (var i = 0; match && i < buf.length; i++) { + match = buf[i] == str.charCodeAt(i); + } + return match; + } + it("file.spec.84 should read file properly, readAsText", function (done) { + runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(evt.target.result).toBe(fileData); + done(); + }); + }); + it("file.spec.84.1 should read JSON file properly, readAsText", function (done) { + var testObject = {key1: "value1", key2: 2}; + runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(evt.target.result).toEqual(JSON.stringify(testObject)); + done(); + }, undefined, undefined, JSON.stringify(testObject)); + }); + it("file.spec.85 should read file properly, Data URI", function (done) { + runReaderTest('readAsDataURL', true, done, null, function (evt, fileData, fileDataAsBinaryString) { + /* `readAsDataURL` function is supported, but the mediatype in Chrome depends on entry name extension, + mediatype in IE is always empty (which is the same as `text-plain` according the specification), + the mediatype in Firefox is always `application/octet-stream`. + For example, if the content is `abcdefg` then Firefox returns `data:application/octet-stream;base64,YWJjZGVmZw==`, + IE returns `data:;base64,YWJjZGVmZw==`, Chrome returns `data:;base64,YWJjZGVmZw==`. */ + expect(evt.target.result).toBeDataUrl(); + + //The atob function it is completely ignored during mobilespec execution, besides the returned object: evt + //it is encoded and the atob function is aimed to decode a string. Even with btoa (encode) the function it gets stucked + //because of the Unicode characters that contains the fileData object. + //Issue reported at JIRA with all the details: CB-7095 + + //expect(evt.target.result.slice(23)).toBe(atob(fileData)); + + done(); + }); + }); + it("file.spec.86 should read file properly, readAsBinaryString", function (done) { + if (isIE) { + /*`readAsBinaryString` function is not supported by IE and has not the stub.*/ + pending(); + } + + runReaderTest('readAsBinaryString', true, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(evt.target.result).toBe(fileDataAsBinaryString); + done(); + }); + }); + it("file.spec.87 should read file properly, readAsArrayBuffer", function (done) { + // Skip test if ArrayBuffers are not supported (e.g.: Android 2.3). + if (typeof window.ArrayBuffer == 'undefined') { + expect(true).toFailWithMessage('Platform does not supported this feature'); + done(); + } + runReaderTest('readAsArrayBuffer', true, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(arrayBufferEqualsString(evt.target.result, fileDataAsBinaryString)).toBe(true); + done(); + }); + }); + it("file.spec.88 should read sliced file: readAsText", function (done) { + runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(evt.target.result).toBe(fileDataAsBinaryString.slice(10, 40)); + done(); + }, 10, 40); + }); + it("file.spec.89 should read sliced file: slice past eof", function (done) { + runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(evt.target.result).toBe(fileData.slice(-5, 9999)); + done(); + }, -5, 9999); + }); + it("file.spec.90 should read sliced file: slice to eof", function (done) { + runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(evt.target.result).toBe(fileData.slice(-5)); + done(); + }, -5); + }); + it("file.spec.91 should read empty slice", function (done) { + runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(evt.target.result).toBe(''); + done(); + }, 0, 0); + }); + it("file.spec.92 should read sliced file properly, readAsDataURL", function (done) { + runReaderTest('readAsDataURL', true, done, null, function (evt, fileData, fileDataAsBinaryString) { + /* `readAsDataURL` function is supported, but the mediatype in Chrome depends on entry name extension, + mediatype in IE is always empty (which is the same as `text-plain` according the specification), + the mediatype in Firefox is always `application/octet-stream`. + For example, if the content is `abcdefg` then Firefox returns `data:application/octet-stream;base64,YWJjZGVmZw==`, + IE returns `data:;base64,YWJjZGVmZw==`, Chrome returns `data:;base64,YWJjZGVmZw==`. */ + expect(evt.target.result).toBeDataUrl(); + + //The atob function it is completely ignored during mobilespec execution, besides the returned object: evt + //it is encoded and the atob function is aimed to decode a string. Even with btoa (encode) the function it gets stucked + //because of the Unicode characters that contains the fileData object. + //Issue reported at JIRA with all the details: CB-7095 + + //expect(evt.target.result.slice(23)).toBe(atob(fileDataAsBinaryString.slice(10, -3))); + + done(); + }, 10, -3); + }); + it("file.spec.93 should read sliced file properly, readAsBinaryString", function (done) { + if (isIE) { + /*`readAsBinaryString` function is not supported by IE and has not the stub.*/ + pending(); + } + + runReaderTest('readAsBinaryString', true, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(evt.target.result).toBe(fileDataAsBinaryString.slice(-10, -5)); + done(); + }, -10, -5); + }); + it("file.spec.94 should read sliced file properly, readAsArrayBuffer", function (done) { + // Skip test if ArrayBuffers are not supported (e.g.: Android 2.3). + if (typeof window.ArrayBuffer == 'undefined') { + expect(true).toFailWithMessage('Platform does not supported this feature'); + done(); + } + runReaderTest('readAsArrayBuffer', true, done, null, function (evt, fileData, fileDataAsBinaryString) { + expect(arrayBufferEqualsString(evt.target.result, fileDataAsBinaryString.slice(0, -1))).toBe(true); + done(); + }, 0, -1); + }); + it("file.spec.94.5 should read large file in multiple chunks, readAsArrayBuffer", function (done) { + // Skip test if ArrayBuffers are not supported (e.g.: Android 2.3). + if (typeof window.ArrayBuffer == 'undefined') { + expect(true).toFailWithMessage('Platform does not supported this feature'); + done(); + } + + var largeText = ""; + for (var i = 0; i < 1000; i++) { + largeText += "Test " + i + "\n"; + } + + // Set the chunk size so that the read will take 5 chunks + FileReader.READ_CHUNK_SIZE = Math.floor(largeText.length / 4) + 1; + + var chunkCount = 0; + var lastProgressValue = -1; + var progressFunc = function (evt) { + expect(evt.loaded).toBeDefined(); + expect(evt.total).toBeDefined(); + + expect(evt.total >= largeText.length).toBe(true); + expect(evt.total <= largeText.length + 5).toBe(true); + expect(evt.loaded > lastProgressValue).toBe(true); + expect(evt.loaded <= evt.total).toBe(true); + + lastProgressValue = evt.loaded; + chunkCount++; + }; + + runReaderTest( + 'readAsArrayBuffer', true, done, progressFunc, + function (evt, fileData, fileDataAsBinaryString) { + expect(arrayBufferEqualsString(evt.target.result, fileDataAsBinaryString.slice(0, -1))).toBe(true); + expect(lastProgressValue >= largeText.length).toBe(true); + expect(lastProgressValue <= largeText.length + 5).toBe(true); + expect(chunkCount).toBe(5); + done(); + }, + 0, -1, largeText); + }); + it("file.spec.94.6 should read large file in multiple chunks, readAsDataURL", function (done) { + var largeText = ""; + for (var i = 0; i < 10; i++) { + largeText += "Test " + i + "\n"; + } + + // Set the chunk size so that the read will take 5 chunks + FileReader.READ_CHUNK_SIZE = Math.floor(largeText.length / 4) + 1; + + var lastProgressValue = 0; + var progressFunc = function (evt) { + expect(evt.total).toBeDefined(); + expect(evt.total).toEqual(largeText.length); + + expect(evt.loaded).toBeDefined(); + expect(evt.loaded).toBeGreaterThan(lastProgressValue); + expect(evt.loaded).toBeLessThan(evt.total + 1); + + lastProgressValue = evt.loaded; + }; + + runReaderTest('readAsDataURL', false, done, progressFunc, + function (evt, fileData, fileDataAsBinaryString) { + expect(function () { + // Cut off data uri prefix + var base64Data = evt.target.result.substring(evt.target.result.indexOf(',') + 1); + expect(window.atob(base64Data)).toEqual(fileData); + }).not.toThrow(); + + expect(lastProgressValue).toEqual(largeText.length); + done(); + }, + undefined, undefined, largeText); + }); + }); + //Read method + describe('FileWriter', function () { + it("file.spec.95 should have correct methods", function (done) { + // retrieve a FileWriter object + var fileName = "writer.methods"; + // FileWriter + root.getFile(fileName, { + create : true + }, function (fileEntry) { + fileEntry.createWriter(function (writer) { + expect(writer).toBeDefined(); + expect(typeof writer.write).toBe('function'); + expect(typeof writer.seek).toBe('function'); + expect(typeof writer.truncate).toBe('function'); + expect(typeof writer.abort).toBe('function'); + // cleanup + deleteFile(fileName, done); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName)); + }); + it("file.spec.96 should be able to write and append to file, createWriter", function (done) { + var fileName = "writer.append.createWriter", // file content + content = "There is an exception to every rule.", // for checkin file length + exception = " Except this one.", + length = content.length; + // create file, then write and append to it + createFile(fileName, function (fileEntry) { + // writes initial file content + fileEntry.createWriter(function (writer) { + //Verifiers declaration + function verifier(evt) { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + // Append some more data + writer.onwriteend = secondVerifier; + length += exception.length; + writer.seek(writer.length); + writer.write(exception); + } + function secondVerifier(evt) { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + var reader = new FileReader(); + reader.onloadend = thirdVerifier; + reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + fileName); + fileEntry.file(function(f){reader.readAsText(f);}); + } + function thirdVerifier(evt) { + expect(evt.target.result).toBe(content+exception); + // cleanup + deleteFile(fileName, done); + } + + //Write process + writer.onwriteend = verifier; + writer.write(content); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.97 should be able to write and append to file, File object", function (done) { + var fileName = "writer.append.File", // file content + content = "There is an exception to every rule.", // for checkin file length + exception = " Except this one.", + length = content.length; + root.getFile(fileName, { + create : true + }, function (fileEntry) { + fileEntry.createWriter(function (writer) { + //Verifiers declaration + function verifier() { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + // Append some more data + writer.onwriteend = secondVerifier; + length += exception.length; + writer.seek(writer.length); + writer.write(exception); + } + function secondVerifier() { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + var reader = new FileReader(); + reader.onloadend = thirdVerifier; + reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + fileName); + fileEntry.file(function(f){reader.readAsText(f);}); + } + function thirdVerifier(evt) { + expect(evt.target.result).toBe(content+exception); + // cleanup + deleteFile(fileName, done); + } + + //Write process + writer.onwriteend = verifier; + writer.write(content); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName)); + }); + it("file.spec.98 should be able to seek to the middle of the file and write more data than file.length", function (done) { + var fileName = "writer.seek.write", // file content + content = "This is our sentence.", // for checking file length + exception = "newer sentence.", + length = content.length; + // create file, then write and append to it + createFile(fileName, function (fileEntry) { + fileEntry.createWriter(function (writer) { + //Verifiers declaration + function verifier(evt) { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + // Append some more data + writer.onwriteend = secondVerifier; + length = 12 + exception.length; + writer.seek(12); + writer.write(exception); + } + function secondVerifier(evt) { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + var reader = new FileReader(); + reader.onloadend = thirdVerifier; + reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + fileName); + fileEntry.file(function(f){reader.readAsText(f);}); + } + function thirdVerifier(evt) { + expect(evt.target.result).toBe(content.substr(0,12)+exception); + // cleanup + deleteFile(fileName, done); + } + + //Write process + writer.onwriteend = verifier; + writer.write(content); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.99 should be able to seek to the middle of the file and write less data than file.length", function (done) { + if (isChrome) { + /* Chrome (re)writes as follows: "This is our sentence." -> "This is new.sentence.", + i.e. the length is not being changed from content.length and writer length will be equal 21 */ + pending(); + } + + var fileName = "writer.seek.write2", // file content + content = "This is our sentence.", // for checking file length + exception = "new.", + length = content.length; + // create file, then write and append to it + createFile(fileName, function (fileEntry) { + fileEntry.createWriter(function (writer) { + // Verifiers declaration + function verifier(evt) { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + // Append some more data + writer.onwriteend = secondVerifier; + length = 8 + exception.length; + writer.seek(8); + writer.write(exception); + } + function secondVerifier(evt) { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + var reader = new FileReader(); + reader.onloadend = thirdVerifier; + reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + fileName); + fileEntry.file(function(f){reader.readAsText(f);}); + } + function thirdVerifier(evt) { + expect(evt.target.result).toBe(content.substr(0,8)+exception); + // cleanup + deleteFile(fileName, done); + } + + //Write process + writer.onwriteend = verifier; + writer.write(content); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.100 should be able to write XML data", function (done) { + var fileName = "writer.xml", // file content + content = '\n\nData\n\n', // for testing file length + length = content.length; + // creates file, then write XML data + createFile(fileName, function (fileEntry) { + fileEntry.createWriter(function (writer) { + //Verifier content + var verifier = function (evt) { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + // cleanup + deleteFile(fileName, done); + }; + //Write process + writer.onwriteend = verifier; + writer.write(content); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.101 should be able to write JSON data", function (done) { + var fileName = "writer.json", // file content + content = '{ "name": "Guy Incognito", "email": "here@there.com" }', // for testing file length + length = content.length; + // creates file, then write JSON content + createFile(fileName, function (fileEntry) { + fileEntry.createWriter(function (writer) { + //Verifier declaration + var verifier = function (evt) { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + // cleanup + deleteFile(fileName, done); + }; + //Write process + writer.onwriteend = verifier; + writer.write(content); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.102 should be able to seek", function (done) { + var fileName = "writer.seek", // file content + content = "There is an exception to every rule. Except this one.", // for testing file length + length = content.length; + // creates file, then write JSON content + createFile(fileName, function (fileEntry) { + // writes file content and tests writer.seek + fileEntry.createWriter(function (writer) { + //Verifier declaration + var verifier = function () { + expect(writer.position).toBe(length); + writer.seek(-5); + expect(writer.position).toBe(length - 5); + writer.seek(length + 100); + expect(writer.position).toBe(length); + writer.seek(10); + expect(writer.position).toBe(10); + // cleanup + deleteFile(fileName, done); + }; + //Write process + writer.onwriteend = verifier; + writer.seek(-100); + expect(writer.position).toBe(0); + writer.write(content); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.103 should be able to truncate", function (done) { + if (isIndexedDBShim) { + /* `abort` and `truncate` functions are not supported (Firefox, IE) */ + pending(); + } + + var fileName = "writer.truncate", + content = "There is an exception to every rule. Except this one."; + // creates file, writes to it, then truncates it + createFile(fileName, function (fileEntry) { + fileEntry.createWriter(function (writer) { + // Verifier declaration + var verifier = function () { + expect(writer.length).toBe(36); + expect(writer.position).toBe(36); + // cleanup + deleteFile(fileName, done); + }; + //Write process + writer.onwriteend = function () { + //Truncate process after write + writer.onwriteend = verifier; + writer.truncate(36); + }; + writer.write(content); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.104 should be able to write binary data from an ArrayBuffer", function (done) { + // Skip test if ArrayBuffers are not supported (e.g.: Android 2.3). + if (typeof window.ArrayBuffer == 'undefined') { + expect(true).toFailWithMessage('Platform does not supported this feature'); + done(); + return; + } + var fileName = "bufferwriter.bin", // file content + data = new ArrayBuffer(32), + dataView = new Int8Array(data), // for verifying file length + length = 32; + for (var i = 0; i < dataView.length; i++) { + dataView[i] = i; + } + // creates file, then write content + createFile(fileName, function (fileEntry) { + // writes file content + fileEntry.createWriter(function (writer) { + //Verifier declaration + var verifier = function () { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + // cleanup + deleteFile(fileName, done); + }; + //Write process + writer.onwriteend = verifier; + writer.write(data); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.105 should be able to write binary data from a Blob", function (done) { + // Skip test if Blobs are not supported (e.g.: Android 2.3). + if ((typeof window.Blob == 'undefined' && typeof window.WebKitBlobBuilder == 'undefined') || typeof window.ArrayBuffer == 'undefined') { + expect(true).toFailWithMessage('Platform does not supported this feature'); + done(); + return; + } + var fileName = "blobwriter.bin", // file content + data = new ArrayBuffer(32), + dataView = new Int8Array(data), + blob, // for verifying file length + length = 32; + for (var i = 0; i < dataView.length; i++) { + dataView[i] = i; + } + try { + // Mobile Safari: Use Blob constructor + blob = new Blob([data], { + "type" : "application/octet-stream" + }); + } catch (e) { + if (window.WebKitBlobBuilder) { + // Android Browser: Use deprecated BlobBuilder + var builder = new WebKitBlobBuilder(); + builder.append(data); + blob = builder.getBlob('application/octet-stream'); + } else { + // We have no way defined to create a Blob, so fail + fail(); + } + } + if (typeof blob !== 'undefined') { + // creates file, then write content + createFile(fileName, function (fileEntry) { + fileEntry.createWriter(function (writer) { + //Verifier declaration + var verifier = function () { + expect(writer.length).toBe(length); + expect(writer.position).toBe(length); + // cleanup + deleteFile(fileName, done); + }; + //Write process + writer.onwriteend = verifier; + writer.write(blob); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + } + }); + it("file.spec.106 should be able to write a File to a FileWriter", function (done) { + var dummyFileName = 'dummy.txt', + outputFileName = 'verify.txt', + dummyFileText = 'This text should be written to two files', + verifier = function (outputFileWriter) { + expect(outputFileWriter.length).toBe(dummyFileText.length); + expect(outputFileWriter.position).toBe(dummyFileText.length); + deleteFile(outputFileName, done); + }, + writeFile = function (fileName, fileData, win) { + var theWriter, + write_file = function (fileEntry) { + // writes file content to new file + fileEntry.createWriter(function (writer) { + theWriter = writer; + writer.onwriteend = function (ev) { + if (typeof fileData.length !== "undefined") { + expect(theWriter.length).toBe(fileData.length); + expect(theWriter.position).toBe(fileData.length); + } + win(theWriter); + }; + writer.onerror = failed.bind(null, done, 'writer.onerror - Error writing content on file: ' + fileName); + writer.write(fileData); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }; + createFile(fileName, write_file, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }, + openFile = function (fileName, callback) { + root.getFile(fileName, { + create : false + }, function (fileEntry) { + fileEntry.file(callback, failed.bind(null, done, 'fileEntry.file - Error reading file using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'root.getFile - Error getting file: ' + fileName)); + }; + writeFile(dummyFileName, dummyFileText, function (dummyFileWriter) { + openFile(dummyFileName, function (file) { + writeFile(outputFileName, file, verifier); + }); + }); + }); + it("file.spec.107 should be able to write a sliced File to a FileWriter", function (done) { + var dummyFileName = 'dummy2.txt', + outputFileName = 'verify2.txt', + dummyFileText = 'This text should be written to two files', + verifier = function (outputFileWriter) { + expect(outputFileWriter.length).toBe(10); + expect(outputFileWriter.position).toBe(10); + deleteFile(outputFileName, done); + }, + writeFile = function (fileName, fileData, win) { + var theWriter, + write_file = function (fileEntry) { + // writes file content to new file + fileEntry.createWriter(function (writer) { + theWriter = writer; + writer.onwriteend = function (ev) { + if (typeof fileData.length !== "undefined") { + expect(theWriter.length).toBe(fileData.length); + expect(theWriter.position).toBe(fileData.length); + } + win(theWriter); + }; + writer.onerror = failed.bind(null, done, 'writer.onerror - Error writing content on file: ' + fileName); + writer.write(fileData); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }; + createFile(fileName, write_file, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }, + openFile = function (fileName, callback) { + root.getFile(fileName, { + create : false + }, function (fileEntry) { + fileEntry.file(callback, failed.bind(null, done, 'fileEntry.file - Error reading file using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'root.getFile - Error getting file: ' + fileName)); + }; + writeFile(dummyFileName, dummyFileText, function (dummyFileWriter) { + openFile(dummyFileName, function (file) { + writeFile(outputFileName, file.slice(10, 20), verifier); + }); + }); + }); + it("file.spec.108 should be able to write binary data from a File", function (done) { + // Skip test if Blobs are not supported (e.g.: Android 2.3). + if (typeof window.Blob == 'undefined' && typeof window.WebKitBlobBuilder == 'undefined') { + expect(true).toFailWithMessage('Platform does not supported this feature'); + done(); + } + var dummyFileName = "blobwriter.bin", + outputFileName = 'verify.bin', // file content + data = new ArrayBuffer(32), + dataView = new Int8Array(data), + blob, // for verifying file length + length = 32, + verifier = function (outputFileWriter) { + expect(outputFileWriter.length).toBe(length); + expect(outputFileWriter.position).toBe(length); + // cleanup + deleteFile(outputFileName); + done(); + }, + writeFile = function (fileName, fileData, win) { + var theWriter, + write_file = function (fileEntry) { + // writes file content to new file + fileEntry.createWriter(function (writer) { + theWriter = writer; + writer.onwriteend = function (ev) { + if (typeof fileData.length !== "undefined") { + expect(theWriter.length).toBe(fileData.length); + expect(theWriter.position).toBe(fileData.length); + } + win(theWriter); + }; + writer.onerror = failed.bind(null, done, 'writer.onerror - Error writing content on file: ' + fileName); + writer.write(fileData); + }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name)); + }; + createFile(fileName, write_file, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }, + openFile = function (fileName, callback) { + root.getFile(fileName, { + create : false + }, function (fileEntry) { + fileEntry.file(callback, failed.bind(null, done, 'fileEntry.file - Error reading file using fileEntry: ' + fileEntry.name)); + }, failed.bind(null, done, 'root.getFile - Error getting file: ' + fileName)); + }; + for (var i = 0; i < dataView.length; i++) { + dataView[i] = i; + } + try { + // Mobile Safari: Use Blob constructor + blob = new Blob([data], { + "type" : "application/octet-stream" + }); + } catch (e) { + if (window.WebKitBlobBuilder) { + // Android Browser: Use deprecated BlobBuilder + var builder = new WebKitBlobBuilder(); + builder.append(data); + blob = builder.getBlob('application/octet-stream'); + } else { + // We have no way defined to create a Blob, so fail + fail(); + } + } + if (typeof blob !== 'undefined') { + // creates file, then write content + writeFile(dummyFileName, blob, function (dummyFileWriter) { + openFile(dummyFileName, function (file) { + writeFile(outputFileName, file, verifier); + }); + }); + } + }); + }); + //FileWritter + describe('Backwards compatibility', function () { + /* These specs exist to test that the File plugin can still recognize file:/// + * URLs, and can resolve them to FileEntry and DirectoryEntry objects. + * They rely on an undocumented interface to File which provides absolute file + * paths, which are not used internally anymore. + * If that interface is not present, then these tests will silently succeed. + */ + it("file.spec.109 should be able to resolve a file:/// URL", function (done) { + var localFilename = 'file.txt'; + var originalEntry; + root.getFile(localFilename, { + create : true + }, function (entry) { + originalEntry = entry; + /* This is an undocumented interface to File which exists only for testing + * backwards compatibilty. By obtaining the raw filesystem path of the download + * location, we can pass that to ft.download() to make sure that previously-stored + * paths are still valid. + */ + cordova.exec(function (localPath) { + window.resolveLocalFileSystemURL("file://" + encodeURI(localPath), function (fileEntry) { + expect(fileEntry.toURL()).toEqual(originalEntry.toURL()); + // cleanup + deleteFile(localFilename); + done(); + }, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving URI: file://' + encodeURI(localPath))); + }, done, 'File', '_getLocalFilesystemPath', [entry.toURL()]); + }, failed.bind(null, done, 'root.getFile - Error creating file: ' + localFilename)); + }); + }); + //Backwards Compatibility + describe('Parent References', function () { + /* These specs verify that paths with parent references i("..") in them + * work correctly, and do not cause the application to crash. + */ + it("file.spec.110 should not throw exception resolving parent refefences", function (done) { + /* This is a direct copy of file.spec.9, with the filename changed, * as reported in CB-5721. + */ + var fileName = "resolve.file.uri"; + var dirName = "resolve.dir.uri"; + // create a new file entry + createDirectory(dirName, function () { + createFile(dirName+"/../" + fileName, function (entry) { + // lookup file system entry + window.resolveLocalFileSystemURL(entry.toURL(), function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.name).toCanonicallyMatch(fileName); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving URI: ' + entry.toURL())); + }, failed.bind(null, done, 'createFile - Error creating file: ../' + fileName)); + }, failed.bind(null, done, 'createDirectory - Error creating directory: ' + dirName)); + }); + it("file.spec.111 should not traverse above above the root directory", function (done) { + var fileName = "traverse.file.uri"; + // create a new file entry + createFile(fileName, function (entry) { + // lookup file system entry + root.getFile('../' + fileName, { + create : false + }, function (fileEntry) { + // Note: we expect this to still resolve, as the correct behaviour is to ignore the ../, not to fail out. + expect(fileEntry).toBeDefined(); + expect(fileEntry.name).toBe(fileName); + expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath +'/' + fileName); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'root.getFile - Error getting file: ../' + fileName)); + }, failed.bind(null, done, 'createFile - Error creating file: ../' + fileName)); + }); + it("file.spec.112 should traverse above above the current directory", function (done) { + var fileName = "traverse2.file.uri", + dirName = "traverse2.subdir"; + // create a new directory and a file entry + createFile(fileName, function () { + createDirectory(dirName, function (entry) { + // lookup file system entry + entry.getFile('../' + fileName, { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.name).toBe(fileName); + expect(fileEntry.fullPath).toCanonicallyMatch('/' + fileName); + // cleanup + deleteEntry(fileName, function () { + deleteEntry(dirName, done); + }); + }, failed.bind(null, done, 'entry.getFile - Error getting file: ' + fileName + ' recently created above: ' + dirName)); + }, failed.bind(null, done, 'createDirectory - Error creating directory: ' + dirName)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.113 getFile: get Entry should error for missing file above root directory", function (done) { + var fileName = "../missing.file"; + // create:false, exclusive:false, file does not exist + root.getFile(fileName, { + create : false + }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not locate nonexistent file: ' + fileName), function (error) { + expect(error).toBeDefined(); + expect(error).toBeFileError(FileError.NOT_FOUND_ERR); + done(); + }); + }); + }); + //Parent References + describe('toNativeURL interface', function () { + /* These specs verify that FileEntries have a toNativeURL method + * which appears to be sane. + */ + var pathExpect = cordova.platformId === 'windowsphone' ? "//nativ" : "file://"; + if (isChrome) { + pathExpect = 'filesystem:file://'; + } + it("file.spec.114 fileEntry should have a toNativeURL method", function (done) { + var fileName = "native.file.uri"; + if (isWindows) { + var rootPath = root.fullPath; + pathExpect = rootPath.substr(0, rootPath.indexOf(":")); + } + // create a new file entry + createFile(fileName, function (entry) { + expect(entry.toNativeURL).toBeDefined(); + expect(entry.name).toCanonicallyMatch(fileName); + expect(typeof entry.toNativeURL).toBe('function'); + var nativeURL = entry.toNativeURL(); + expect(typeof nativeURL).toBe("string"); + expect(nativeURL.substring(0, pathExpect.length)).toEqual(pathExpect); + expect(nativeURL.substring(nativeURL.length - fileName.length)).toEqual(fileName); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.115 DirectoryReader should return entries with toNativeURL method", function (done) { + var dirName = 'nativeEntries.dir', + fileName = 'nativeEntries.file', + directory, + checkEntries = function (entries) { + expect(entries).toBeDefined(); + expect(entries instanceof Array).toBe(true); + expect(entries.length).toBe(1); + expect(entries[0].toNativeURL).toBeDefined(); + expect(typeof entries[0].toNativeURL).toBe('function'); + var nativeURL = entries[0].toNativeURL(); + expect(typeof nativeURL).toBe("string"); + expect(nativeURL.substring(0, pathExpect.length)).toEqual(pathExpect); + expect(nativeURL.substring(nativeURL.length - fileName.length)).toEqual(fileName); + // cleanup + directory.removeRecursively(null, null); + done(); + }; + // create a new file entry + root.getDirectory(dirName, { + create : true + }, function (dir) { + directory = dir; + directory.getFile(fileName, { + create : true + }, function (fileEntry) { + var reader = directory.createReader(); + reader.readEntries(checkEntries, failed.bind(null, done, 'reader.readEntries - Error reading entries from directory: ' + dirName)); + }, failed.bind(null, done, 'directory.getFile - Error creating file: ' + fileName)); + }, failed.bind(null, done, 'root.getDirectory - Error creating directory: ' + dirName)); + }); + it("file.spec.116 resolveLocalFileSystemURL should return entries with toNativeURL method", function (done) { + var fileName = "native.resolve.uri"; + // create a new file entry + createFile(fileName, function (entry) { + resolveLocalFileSystemURL(entry.toURL(), function (entry) { + expect(entry.toNativeURL).toBeDefined(); + expect(entry.name).toCanonicallyMatch(fileName); + expect(typeof entry.toNativeURL).toBe('function'); + var nativeURL = entry.toNativeURL(); + expect(typeof nativeURL).toBe("string"); + expect(nativeURL.substring(0, pathExpect.length)).toEqual(pathExpect); + expect(nativeURL.substring(nativeURL.length - fileName.length)).toEqual(fileName); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + entry.toURL())); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + }); + //toNativeURL interface + describe('resolveLocalFileSystemURL on file://', function () { + /* These specs verify that window.resolveLocalFileSystemURL works correctly on file:// URLs + */ + it("file.spec.117 should not resolve native URLs outside of FS roots", function (done) { + // lookup file system entry + window.resolveLocalFileSystemURL("file:///this.is.an.invalid.url", succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Unexpected success callback, it should not resolve invalid URL: file:///this.is.an.invalid.url'), function (error) { + expect(error).toBeDefined(); + done(); + }); + }); + it("file.spec.118 should not resolve native URLs outside of FS roots", function (done) { + // lookup file system entry + window.resolveLocalFileSystemURL("file://localhost/this.is.an.invalid.url", succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Unexpected success callback, it should not resolve invalid URL: file://localhost/this.is.an.invalid.url'), function (error) { + expect(error).toBeDefined(); + done(); + }); + }); + it("file.spec.119 should not resolve invalid native URLs", function (done) { + // lookup file system entry + window.resolveLocalFileSystemURL("file://localhost", succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Unexpected success callback, it should not resolve invalid URL: file://localhost'), function (error) { + expect(error).toBeDefined(); + done(); + }); + }); + it("file.spec.120 should not resolve invalid native URLs with query strings", function (done) { + // lookup file system entry + window.resolveLocalFileSystemURL("file://localhost?test/test", succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Unexpected success callback, it should not resolve invalid URL: file://localhost?test/test'), function (error) { + expect(error).toBeDefined(); + done(); + }); + }); + it("file.spec.121 should resolve native URLs returned by API", function (done) { + var fileName = "native.resolve.uri1"; + // create a new file entry + createFile(fileName, function (entry) { + resolveLocalFileSystemURL(entry.toNativeURL(), function (fileEntry) { + expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath + "/" + fileName); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + entry.toNativeURL())); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.122 should resolve native URLs returned by API with localhost", function (done) { + var fileName = "native.resolve.uri2"; + // create a new file entry + createFile(fileName, function (entry) { + var url = entry.toNativeURL(); + url = url.replace("///", "//localhost/"); + resolveLocalFileSystemURL(url, function (fileEntry) { + expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath + "/" + fileName); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + url)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.123 should resolve native URLs returned by API with query string", function (done) { + var fileName = "native.resolve.uri3"; + // create a new file entry + createFile(fileName, function (entry) { + var url = entry.toNativeURL(); + url = url + "?test/test"; + resolveLocalFileSystemURL(url, function (fileEntry) { + expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath + "/" + fileName); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + url)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + it("file.spec.124 should resolve native URLs returned by API with localhost and query string", function (done) { + var fileName = "native.resolve.uri4"; + // create a new file entry + createFile(fileName, function (entry) { + var url = entry.toNativeURL(); + url = url.replace("///", "//localhost/") + "?test/test"; + resolveLocalFileSystemURL(url, function (fileEntry) { + expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath + "/" + fileName); + // cleanup + deleteEntry(fileName, done); + }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + url)); + }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName)); + }); + }); + //resolveLocalFileSystemURL on file:// + describe('cross-file-system copy and move', function () { + /* These specs verify that Entry.copyTo and Entry.moveTo work correctly + * when crossing filesystem boundaries. + */ + it("file.spec.125 copyTo: temporary -> persistent", function (done) { + var file1 = "entry.copy.file1a", + file2 = "entry.copy.file2a", + sourceEntry, + fullPath = joinURL(root.fullPath, file2), + validateFile = function (entry) { + // a bit redundant since copy returned this entry already + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(file2); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + expect(entry.filesystem).toBeDefined(); + if (isChrome) { + expect(entry.filesystem.name).toContain("Persistent"); + } else { + expect(entry.filesystem.name).toEqual("persistent"); + } + // cleanup + deleteEntry(entry.name); + deleteEntry(sourceEntry.name, done); + }, + createSourceAndTransfer = function () { + temp_root.getFile(file1, { + create : true + }, function (entry) { + expect(entry.filesystem).toBeDefined(); + if (isChrome) { + expect(entry.filesystem.name).toContain("Temporary"); + } else { + expect(entry.filesystem.name).toEqual("temporary"); + } + sourceEntry = entry; + // Save for later cleanup + entry.copyTo(persistent_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + file1 + ' to PERSISTENT root as: ' + file2)); + }, failed.bind(null, done, 'temp_root.getFile - Error creating file: ' + file1 + 'at TEMPORAL root')); + }; + // Delete any existing file to start things off + persistent_root.getFile(file2, {}, function (entry) { + entry.remove(createSourceAndTransfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2)); + }, createSourceAndTransfer); + }); + it("file.spec.126 copyTo: persistent -> temporary", function (done) { + var file1 = "entry.copy.file1b", + file2 = "entry.copy.file2b", + sourceEntry, + fullPath = joinURL(temp_root.fullPath, file2), + validateFile = function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(file2); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + if (isChrome) { + expect(entry.filesystem.name).toContain("Temporary"); + } else { + expect(entry.filesystem.name).toEqual("temporary"); + } + // cleanup + deleteEntry(entry.name); + deleteEntry(sourceEntry.name, done); + }, + createSourceAndTransfer = function () { + persistent_root.getFile(file1, { + create : true + }, function (entry) { + expect(entry).toBeDefined(); + expect(entry.filesystem).toBeDefined(); + if (isChrome) { + expect(entry.filesystem.name).toContain("Persistent"); + } else { + expect(entry.filesystem.name).toEqual("persistent"); + } + sourceEntry = entry; + // Save for later cleanup + entry.copyTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + file1 + ' to TEMPORAL root as: ' + file2)); + }, failed.bind(null, done, 'persistent_root.getFile - Error creating file: ' + file1 + 'at PERSISTENT root')); + }; + // Delete any existing file to start things off + temp_root.getFile(file2, {}, function (entry) { + entry.remove(createSourceAndTransfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2)); + }, createSourceAndTransfer); + }); + it("file.spec.127 moveTo: temporary -> persistent", function (done) { + var file1 = "entry.copy.file1a", + file2 = "entry.copy.file2a", + sourceEntry, + fullPath = joinURL(root.fullPath, file2), + validateFile = function (entry) { + // a bit redundant since copy returned this entry already + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(file2); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + expect(entry.filesystem).toBeDefined(); + if (isChrome) { + expect(entry.filesystem.name).toContain("Persistent"); + } else { + expect(entry.filesystem.name).toEqual("persistent"); + } + // cleanup + deleteEntry(entry.name); + deleteEntry(sourceEntry.name, done); + }, + createSourceAndTransfer = function () { + temp_root.getFile(file1, { + create : true + }, function (entry) { + expect(entry.filesystem).toBeDefined(); + if (isChrome) { + expect(entry.filesystem.name).toContain("Temporary"); + } else { + expect(entry.filesystem.name).toEqual("temporary"); + } + sourceEntry = entry; + // Save for later cleanup + entry.moveTo(persistent_root, file2, validateFile, failed.bind(null, done, 'entry.moveTo - Error moving file: ' + file1 + ' to PERSISTENT root as: ' + file2)); + }, failed.bind(null, done, 'temp_root.getFile - Error creating file: ' + file1 + 'at TEMPORAL root')); + }; + // Delete any existing file to start things off + persistent_root.getFile(file2, {}, function (entry) { + entry.remove(createSourceAndTransfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2)); + }, createSourceAndTransfer); + }); + it("file.spec.128 moveTo: persistent -> temporary", function (done) { + var file1 = "entry.copy.file1b", + file2 = "entry.copy.file2b", + sourceEntry, + fullPath = joinURL(temp_root.fullPath, file2), + validateFile = function (entry) { + expect(entry).toBeDefined(); + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(file2); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + if(isChrome) { + expect(entry.filesystem.name).toContain("Temporary"); + } else { + expect(entry.filesystem.name).toEqual("temporary"); + } + // cleanup + deleteEntry(entry.name); + deleteEntry(sourceEntry.name, done); + }, + createSourceAndTransfer = function () { + persistent_root.getFile(file1, { + create : true + }, function (entry) { + expect(entry).toBeDefined(); + expect(entry.filesystem).toBeDefined(); + if (isChrome) { + expect(entry.filesystem.name).toContain("Persistent"); + } else { + expect(entry.filesystem.name).toEqual("persistent"); + } + sourceEntry = entry; + // Save for later cleanup + entry.moveTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.moveTo - Error moving file: ' + file1 + ' to TEMPORAL root as: ' + file2)); + }, failed.bind(null, done, 'persistent_root.getFile - Error creating file: ' + file1 + 'at PERSISTENT root')); + }; + // Delete any existing file to start things off + temp_root.getFile(file2, {}, function (entry) { + entry.remove(createSourceAndTransfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2)); + }, createSourceAndTransfer); + }); + it("file.spec.129 cordova.file.*Directory are set", function () { + var expectedPaths = ['applicationDirectory', 'applicationStorageDirectory', 'dataDirectory', 'cacheDirectory']; + if (cordova.platformId == 'android' || cordova.platformId == 'amazon-fireos') { + if (cordova.file.externalApplicationStorageDirectory !== null) { + // https://issues.apache.org/jira/browse/CB-10411 + // If external storage can't be mounted, the cordova.file.external* properties are null. + expectedPaths.push('externalApplicationStorageDirectory', 'externalRootDirectory', 'externalCacheDirectory', 'externalDataDirectory'); + } + } else if (cordova.platformId == 'blackberry10') { + expectedPaths.push('externalRootDirectory', 'sharedDirectory'); + } else if (cordova.platformId == 'ios') { + expectedPaths.push('syncedDataDirectory', 'documentsDirectory', 'tempDirectory'); + } else if (cordova.platformId == 'osx') { + expectedPaths.push('documentsDirectory', 'tempDirectory', 'rootDirectory'); + } else { + console.log('Skipping test due on unsupported platform.'); + return; + } + for (var i = 0; i < expectedPaths.length; ++i) { + expect(typeof cordova.file[expectedPaths[i]]).toBe('string'); + expect(cordova.file[expectedPaths[i]]).toMatch(/\/$/, 'Path should end with a slash'); + } + }); + }); + describe('resolveLocalFileSystemURL on cdvfile://', function () { + it("file.spec.147 should be able to resolve cdvfile applicationDirectory fs root", function(done) { + var cdvfileApplicationDirectoryFsRootName; + if (cordova.platformId === 'android') { + cdvfileApplicationDirectoryFsRootName = 'assets'; + } else if (cordova.platformId === 'ios') { + cdvfileApplicationDirectoryFsRootName = 'bundle'; + } else { + pending(); + } + + resolveLocalFileSystemURL('cdvfile://localhost/' + cdvfileApplicationDirectoryFsRootName + '/', function(applicationDirectoryRoot) { + expect(applicationDirectoryRoot.isFile).toBe(false); + expect(applicationDirectoryRoot.isDirectory).toBe(true); + expect(applicationDirectoryRoot.name).toCanonicallyMatch(''); + expect(applicationDirectoryRoot.fullPath).toCanonicallyMatch('/'); + expect(applicationDirectoryRoot.filesystem.name).toEqual(cdvfileApplicationDirectoryFsRootName); + + // Requires HelloCordova www assets, in config.xml or + // cdvfile: in CSP and in config.xml + resolveLocalFileSystemURL('cdvfile://localhost/' + cdvfileApplicationDirectoryFsRootName + '/www/img/logo.png', function(entry) { + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch('logo.png'); + expect(entry.fullPath).toCanonicallyMatch('/www/img/logo.png'); + expect(entry.filesystem.name).toEqual(cdvfileApplicationDirectoryFsRootName); + + var img = new Image(); + img.onerror = function(err) { + expect(err).not.toBeDefined(); + done(); + }; + img.onload = function() { + done(); + }; + img.src = entry.toInternalURL(); + }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for cdvfile applicationDirectory')); + }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for cdvfile applicationDirectory')); + }); + }); + //cross-file-system copy and move + describe('IndexedDB-based impl', function () { + it("file.spec.131 Nested file or nested directory should be removed when removing a parent directory", function (done) { + var parentDirName = 'deletedDir131', + nestedDirName = 'nestedDir131', + nestedFileName = 'nestedFile131.txt'; + + createDirectory(parentDirName, function (parent) { + parent.getDirectory(nestedDirName, { create: true}, function () { + parent.getFile(nestedFileName, { create: true}, function () { + parent.removeRecursively(function() { + root.getDirectory(parentDirName,{ create: false}, failed.bind(this, done, 'root.getDirectory - unexpected success callback : ' + parentDirName), function(){ + parent.getFile(nestedFileName,{ create: false}, failed.bind(this, done, 'getFile - unexpected success callback : ' + nestedFileName), function(){ + parent.getDirectory(nestedDirName, { create: false}, failed.bind(this, done, 'getDirectory - unexpected success callback : ' + nestedDirName), done); + }); + }); + }, failed.bind(this, done, 'removeRecursively - Error removing directory : ' + parentDirName)); + }, failed.bind(this, done, 'getFile - Error creating file : ' + nestedFileName)); + },failed.bind(this, done, 'getDirectory - Error creating directory : ' + nestedDirName)); + }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + parentDirName)); + }); + it("file.spec.132 Entry should be created succesfully when using relative paths if its parent directory exists", function (done) { + /* Directory entries have to be created successively. + For example, the call `fs.root.getDirectory('dir1/dir2', {create:true}, successCallback, errorCallback)` + will fail if dir1 did not exist. */ + var parentName = 'parentName132'; + var nestedName = 'nestedName132'; + var path = parentName + '/' + nestedName; + + var win = function(directory){ + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(nestedName); + expect(directory.fullPath).toCanonicallyMatch('/' + path + '/'); + deleteEntry(directory.name); + deleteEntry(parentName, done); + }; + + createDirectory(parentName, function() { + root.getDirectory(parentName + '/' + nestedName, {create:true}, win, + failed.bind(this, done, 'root.getDirectory - Error getting directory : ' + path)); + }, failed.bind(this, done, 'root.getDirectory - Error getting directory : ' + parentName)); + }); + it("file.spec.133 A file being removed should not affect another file with name being a prefix of the removed file name.", function (done) { + + // Names include special symbols so that we check the IndexedDB range used + var deletedFileName = 'deletedFile.0', + secondFileName = 'deletedFile.0.1'; + + var win = function(fileEntry){ + expect(fileEntry).toBeDefined(); + expect(fileEntry.isFile).toBe(true); + expect(fileEntry.isDirectory).toBe(false); + expect(fileEntry.name).toCanonicallyMatch(secondFileName); + deleteEntry(fileEntry.name, done); + }; + + createFile(deletedFileName, function (deletedFile) { + createFile(secondFileName, function () { + deletedFile.remove(function() { + root.getFile(deletedFileName, {create: false}, failed.bind(this, done, 'getFile - unexpected success callback getting deleted file : ' + deletedFileName), function(){ + root.getFile(secondFileName, {create: false}, win, failed.bind(this, done, 'getFile - Error getting file after deleting deletedFile : ' + secondFileName)); + }); + }, failed.bind(this, done, 'remove - Error removing file : ' + deletedFileName)); + }, failed.bind(this, done, 'getFile - Error creating file : ' + secondFileName)); + }, failed.bind(this, done, 'getFile - Error creating file : ' + deletedFileName)); + }); + it("file.spec.134 A directory being removed should not affect another directory with name being a prefix of the removed directory name.", function (done) { + + // Names include special symbols so that we check the IndexedDB range used + var deletedDirName = 'deletedDir.0', + secondDirName = 'deletedDir.0.1'; + + var win = function(directory){ + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(secondDirName); + deleteEntry(directory.name, done); + }; + + createDirectory(deletedDirName, function (deletedDir) { + createDirectory(secondDirName, function () { + deletedDir.remove(function() { + root.getDirectory(deletedDirName, {create: false}, failed.bind(this, done, 'getDirectory - unexpected success callback getting deleted directory : ' + deletedDirName), function() { + root.getDirectory(secondDirName, {create: false}, win, failed.bind(this, done, 'getDirectory - Error getting directory after deleting deletedDirectory : ' + secondDirName)); + }); + }, failed.bind(this, done, 'remove - Error removing directory : ' + deletedDirName)); + }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + secondDirName)); + }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + deletedDirName)); + }); + it("file.spec.135 Deletion of a child directory should not affect the parent directory.", function (done) { + + var parentName = 'parentName135'; + var childName = 'childName135'; + + var win = function(directory){ + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(parentName); + deleteEntry(directory.name, done); + }; + + createDirectory(parentName, function(parent){ + parent.getDirectory(childName, {create: true}, function(child){ + child.removeRecursively(function(){ + root.getDirectory(parentName, {create: false}, win, failed.bind(this, done, 'root.getDirectory - Error getting parent directory : ' + parentName)); + }, + failed.bind(this, done, 'getDirectory - Error removing directory : ' + childName)); + }, failed.bind(this, done, 'getDirectory - Error creating directory : ' + childName)); + }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + parentName)); + }); + it("file.spec.136 Paths should support Unicode symbols.", function (done) { + + var dirName = '文件插件'; + + var win = function(directory){ + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.name).toCanonicallyMatch(dirName); + deleteEntry(directory.name, done); + }; + + createDirectory(dirName, function(){ + root.getDirectory(dirName, {create: false}, win, + failed.bind(this, done, 'root.getDirectory - Error getting directory : ' + dirName)); + }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + dirName)); + }); + }); + // Content and Asset URLs + if (cordova.platformId == 'android') { + describe('content: URLs', function() { + // Warning: Default HelloWorld www directory structure is required for these tests (www/index.html at least) + function testContentCopy(src, done) { + var file2 = "entry.copy.file2b", + fullPath = joinURL(temp_root.fullPath, file2), + validateFile = function (entry) { + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(file2); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + expect(entry.filesystem.name).toEqual("temporary"); + // cleanup + deleteEntry(entry.name, done); + }, + transfer = function () { + resolveLocalFileSystemURL(src, function(entry) { + expect(entry).toBeDefined(); + expect(entry.filesystem.name).toEqual("content"); + entry.copyTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + entry.toURL() + ' to TEMPORAL root as: ' + file2)); + }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for content provider')); + }; + // Delete any existing file to start things off + temp_root.getFile(file2, {}, function (entry) { + entry.remove(transfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2)); + }, transfer); + } + it("file.spec.138 copyTo: content", function(done) { + testContentCopy('content://org.apache.cordova.file.testprovider/www/index.html', done); + }); + it("file.spec.139 copyTo: content /w space and query", function(done) { + testContentCopy('content://org.apache.cordova.file.testprovider/?name=foo%20bar&realPath=%2Fwww%2Findex.html', done); + }); + it("file.spec.140 delete: content should fail", function(done) { + resolveLocalFileSystemURL('content://org.apache.cordova.file.testprovider/www/index.html', function(entry) { + entry.remove(failed.bind(null, done, 'expected delete to fail'), done); + }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for content provider')); + }); + }); + + // these tests ensure that you can read and copy from android_asset folder + // for details see https://issues.apache.org/jira/browse/CB-6428 + // and https://mail-archives.apache.org/mod_mbox/cordova-dev/201508.mbox/%3C782154441.8406572.1440182722528.JavaMail.yahoo%40mail.yahoo.com%3E + describe('asset: URLs', function() { + it("file.spec.141 filePaths.applicationStorage", function() { + expect(cordova.file.applicationDirectory).toEqual('file:///android_asset/'); + }, MEDIUM_TIMEOUT); + it("file.spec.142 assets should be enumerable", function(done) { + resolveLocalFileSystemURL('file:///android_asset/www/fixtures/asset-test', function(entry) { + var reader = entry.createReader(); + reader.readEntries(function (entries) { + expect(entries.length).not.toBe(0); + done(); + }, failed.bind(null, done, 'reader.readEntries - Error during reading of entries from assets directory')); + }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets')); + }, MEDIUM_TIMEOUT); + it("file.spec.145 asset subdirectories should be obtainable", function(done) { + resolveLocalFileSystemURL('file:///android_asset/www/fixtures', function(entry) { + entry.getDirectory('asset-test', { create: false }, function (subDir) { + expect(subDir).toBeDefined(); + expect(subDir.isFile).toBe(false); + expect(subDir.isDirectory).toBe(true); + expect(subDir.name).toCanonicallyMatch('asset-test'); + done(); + }, failed.bind(null, done, 'entry.getDirectory - Error getting asset subdirectory')); + }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets')); + }, MEDIUM_TIMEOUT); + it("file.spec.146 asset files should be readable", function(done) { + resolveLocalFileSystemURL('file:///android_asset/www/fixtures/asset-test/asset-test.txt', function(entry) { + expect(entry.isFile).toBe(true); + entry.file(function (file) { + expect(file).toBeDefined(); + var reader = new FileReader(); + reader.onerror = failed.bind(null, done, 'reader.readAsText - Error reading asset text file'); + reader.onloadend = function () { + expect(this.result).toBeDefined(); + expect(this.result.length).not.toBe(0); + done(); + }; + reader.readAsText(file); + }, failed.bind(null, done, 'entry.file - Error reading asset file')); + }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets')); + }, MEDIUM_TIMEOUT); + it("file.spec.143 copyTo: asset -> temporary", function(done) { + var file2 = "entry.copy.file2b", + fullPath = joinURL(temp_root.fullPath, file2), + validateFile = function (entry) { + expect(entry.isFile).toBe(true); + expect(entry.isDirectory).toBe(false); + expect(entry.name).toCanonicallyMatch(file2); + expect(entry.fullPath).toCanonicallyMatch(fullPath); + expect(entry.filesystem.name).toEqual("temporary"); + // cleanup + deleteEntry(entry.name, done); + }, + transfer = function () { + resolveLocalFileSystemURL('file:///android_asset/www/index.html', function(entry) { + expect(entry.filesystem.name).toEqual('assets'); + entry.copyTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + entry.toURL() + ' to TEMPORAL root as: ' + file2)); + }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets')); + }; + // Delete any existing file to start things off + temp_root.getFile(file2, {}, function (entry) { + entry.remove(transfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2)); + }, transfer); + }, MEDIUM_TIMEOUT); + }); + it("file.spec.144 copyTo: asset directory", function (done) { + var srcUrl = 'file:///android_asset/www/fixtures/asset-test'; + var dstDir = "entry.copy.dstDir"; + var dstPath = joinURL(root.fullPath, dstDir); + // create a new directory entry to kick off it + deleteEntry(dstDir, function () { + resolveLocalFileSystemURL(srcUrl, function(directory) { + directory.copyTo(root, dstDir, function (directory) { + expect(directory).toBeDefined(); + expect(directory.isFile).toBe(false); + expect(directory.isDirectory).toBe(true); + expect(directory.fullPath).toCanonicallyMatch(dstPath); + expect(directory.name).toCanonicallyMatch(dstDir); + root.getDirectory(dstDir, { + create : false + }, function (dirEntry) { + expect(dirEntry).toBeDefined(); + expect(dirEntry.isFile).toBe(false); + expect(dirEntry.isDirectory).toBe(true); + expect(dirEntry.fullPath).toCanonicallyMatch(dstPath); + expect(dirEntry.name).toCanonicallyMatch(dstDir); + dirEntry.getFile('asset-test.txt', { + create : false + }, function (fileEntry) { + expect(fileEntry).toBeDefined(); + expect(fileEntry.isFile).toBe(true); + // cleanup + deleteEntry(dstDir, done); + }, failed.bind(null, done, 'dirEntry.getFile - Error getting subfile')); + }, failed.bind(null, done, 'root.getDirectory - Error getting copied directory')); + }, failed.bind(null, done, 'directory.copyTo - Error copying directory')); + }, failed.bind(null, done, 'resolving src dir')); + }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir)); + }, MEDIUM_TIMEOUT); + } + }); + +}; +//****************************************************************************************** +//***************************************Manual Tests*************************************** +//****************************************************************************************** + +exports.defineManualTests = function (contentEl, createActionButton) { + + function resolveFs(fsname) { + var fsURL = "cdvfile://localhost/" + fsname + "/"; + logMessage("Resolving URL: " + fsURL); + resolveLocalFileSystemURL(fsURL, function (entry) { + logMessage("Success", 'green'); + logMessage(entry.toURL(), 'blue'); + logMessage(entry.toInternalURL(), 'blue'); + logMessage("Resolving URL: " + entry.toURL()); + resolveLocalFileSystemURL(entry.toURL(), function (entry2) { + logMessage("Success", 'green'); + logMessage(entry2.toURL(), 'blue'); + logMessage(entry2.toInternalURL(), 'blue'); + }, logError("resolveLocalFileSystemURL")); + }, logError("resolveLocalFileSystemURL")); + } + + function testPrivateURL() { + requestFileSystem(LocalFileSystem.TEMPORARY, 0, function (fileSystem) { + logMessage("Temporary root is at " + fileSystem.root.toNativeURL()); + fileSystem.root.getFile("testfile", { + create : true + }, function (entry) { + logMessage("Temporary file is at " + entry.toNativeURL()); + if (entry.toNativeURL().substring(0, 12) == "file:///var/") { + logMessage("File starts with /var/, trying /private/var"); + var newURL = "file://localhost/private/var/" + entry.toNativeURL().substring(12) + "?and=another_thing"; + //var newURL = entry.toNativeURL(); + logMessage(newURL, 'blue'); + resolveLocalFileSystemURL(newURL, function (newEntry) { + logMessage("Successfully resolved.", 'green'); + logMessage(newEntry.toURL(), 'blue'); + logMessage(newEntry.toNativeURL(), 'blue'); + }, logError("resolveLocalFileSystemURL")); + } + }, logError("getFile")); + }, logError("requestFileSystem")); + } + + function resolveFsContactImage() { + navigator.contacts.pickContact(function(contact) { + var logBox = document.getElementById("logContactBox"); + logBox.innerHTML = ""; + var resolveResult = document.createElement("p"); + if (contact.photos) { + var photoURL = contact.photos[0].value; + resolveLocalFileSystemURL(photoURL, function(entry) { + var contactImage = document.createElement("img"); + var contactLabelImage = document.createElement("p"); + contactLabelImage.innerHTML = "Result contact image"; + contactImage.setAttribute("src", entry.toURL()); + resolveResult.innerHTML = "Success resolve\n" + entry.toURL(); + logBox.appendChild(contactLabelImage); + logBox.appendChild(contactImage); + logBox.appendChild(resolveResult); + }, + function(err) { + console.log("resolve error" + err); + }); + } + else { + resolveResult.innerHTML = "Contact has no photos"; + logBox.appendChild(resolveResult); + } + }, + function(err) { + console.log("contact pick error" + err); + }); + } + + function clearLog() { + var log = document.getElementById("info"); + log.innerHTML = ""; + } + + function logMessage(message, color) { + var log = document.getElementById("info"); + var logLine = document.createElement('div'); + if (color) { + logLine.style.color = color; + } + logLine.innerHTML = message; + log.appendChild(logLine); + } + + function logError(serviceName) { + return function (err) { + logMessage("ERROR: " + serviceName + " " + JSON.stringify(err), "red"); + }; + } + + var fsRoots = { + "ios" : "library,library-nosync,documents,documents-nosync,cache,bundle,root,private", + "osx" : "library,library-nosync,documents,documents-nosync,cache,bundle,root,private", + "android" : "files,files-external,documents,sdcard,cache,cache-external,assets,root", + "amazon-fireos" : "files,files-external,documents,sdcard,cache,cache-external,root", + "windows": "temporary,persistent" + }; + + //Add title and align to content + var div = document.createElement('h2'); + div.appendChild(document.createTextNode('File Systems')); + div.setAttribute("align", "center"); + contentEl.appendChild(div); + + div = document.createElement('h3'); + div.appendChild(document.createTextNode('Results are displayed in yellow status box below with expected results noted under that')); + div.setAttribute("align", "center"); + contentEl.appendChild(div); + + div = document.createElement('div'); + div.setAttribute("id", "button"); + div.setAttribute("align", "center"); + contentEl.appendChild(div); + if (fsRoots.hasOwnProperty(cordova.platformId)) { + (fsRoots[cordova.platformId].split(',')).forEach(function (fs) { + if (cordova.platformId === 'ios' && fs === 'private') { + createActionButton("Test private URL (iOS)", function () { + clearLog(); + testPrivateURL(); + }, 'button'); + } else { + createActionButton(fs, function () { + clearLog(); + resolveFs(fs); + }, 'button'); + } + }); + } + + + div = document.createElement('div'); + div.setAttribute("id", "info"); + div.setAttribute("align", "center"); + contentEl.appendChild(div); + + div = document.createElement('h3'); + div.appendChild(document.createTextNode('For each test above, file or directory should be successfully found. ' + + 'Status box should say Resolving URL was Success. The first URL resolved is the internal URL. ' + + 'The second URL resolved is the absolute URL. Blue URLs must match.')); + contentEl.appendChild(div); + + div = document.createElement('h3'); + div.appendChild(document.createTextNode('For Test private URL (iOS), the private URL (first blue URL in status box) ' + + 'should be successfully resolved. Status box should say Successfully resolved. Both blue URLs below ' + + 'that should match.')); + contentEl.appendChild(div); + + div = document.createElement('h2'); + div.appendChild(document.createTextNode('Resolving content urls')); + div.setAttribute("align", "center"); + contentEl.appendChild(div); + + div = document.createElement('div'); + div.setAttribute("id", "contactButton"); + div.setAttribute("align", "center"); + contentEl.appendChild(div); + + div = document.createElement('div'); + div.setAttribute("id", "logContactBox"); + div.setAttribute("align", "center"); + contentEl.appendChild(div); + + createActionButton('show-contact-image', function () { + resolveFsContactImage(); + }, 'contactButton'); +}; diff --git a/mobile/plugins/cordova-plugin-file/tests/www/fixtures/asset-test/asset-test.txt b/mobile/plugins/cordova-plugin-file/tests/www/fixtures/asset-test/asset-test.txt new file mode 100644 index 0000000..2ee2df0 --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/tests/www/fixtures/asset-test/asset-test.txt @@ -0,0 +1 @@ +This file is here for testing purposes \ No newline at end of file diff --git a/mobile/plugins/cordova-plugin-file/www/DirectoryEntry.js b/mobile/plugins/cordova-plugin-file/www/DirectoryEntry.js new file mode 100644 index 0000000..62f468a --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/www/DirectoryEntry.js @@ -0,0 +1,117 @@ +/* + * + * 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. + * +*/ + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + Entry = require('./Entry'), + FileError = require('./FileError'), + DirectoryReader = require('./DirectoryReader'); + +/** + * An interface representing a directory on the file system. + * + * {boolean} isFile always false (readonly) + * {boolean} isDirectory always true (readonly) + * {DOMString} name of the directory, excluding the path leading to it (readonly) + * {DOMString} fullPath the absolute full path to the directory (readonly) + * {FileSystem} filesystem on which the directory resides (readonly) + */ +var DirectoryEntry = function(name, fullPath, fileSystem, nativeURL) { + + // add trailing slash if it is missing + if ((fullPath) && !/\/$/.test(fullPath)) { + fullPath += "/"; + } + // add trailing slash if it is missing + if (nativeURL && !/\/$/.test(nativeURL)) { + nativeURL += "/"; + } + DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, fileSystem, nativeURL); +}; + +utils.extend(DirectoryEntry, Entry); + +/** + * Creates a new DirectoryReader to read entries from this directory + */ +DirectoryEntry.prototype.createReader = function() { + return new DirectoryReader(this.toInternalURL()); +}; + +/** + * Creates or looks up a directory + * + * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory + * @param {Flags} options to create or exclusively create the directory + * @param {Function} successCallback is called with the new entry + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments); + var fs = this.filesystem; + var win = successCallback && function(result) { + var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL); + successCallback(entry); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getDirectory", [this.toInternalURL(), path, options]); +}; + +/** + * Deletes a directory and all of it's contents + * + * @param {Function} successCallback is called with no parameters + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) { + argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments); + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(successCallback, fail, "File", "removeRecursively", [this.toInternalURL()]); +}; + +/** + * Creates or looks up a file + * + * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file + * @param {Flags} options to create or exclusively create the file + * @param {Function} successCallback is called with the new entry + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments); + var fs = this.filesystem; + var win = successCallback && function(result) { + var FileEntry = require('./FileEntry'); + var entry = new FileEntry(result.name, result.fullPath, fs, result.nativeURL); + successCallback(entry); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getFile", [this.toInternalURL(), path, options]); +}; + +module.exports = DirectoryEntry; diff --git a/mobile/plugins/cordova-plugin-file/www/DirectoryReader.js b/mobile/plugins/cordova-plugin-file/www/DirectoryReader.js new file mode 100644 index 0000000..2894c9a --- /dev/null +++ b/mobile/plugins/cordova-plugin-file/www/DirectoryReader.js @@ -0,0 +1,73 @@ +/* + * + * 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. + * +*/ + +var exec = require('cordova/exec'), + FileError = require('./FileError') ; + +/** + * An interface that lists the files and directories in a directory. + */ +function DirectoryReader(localURL) { + this.localURL = localURL || null; + this.hasReadEntries = false; +} + +/** + * Returns a list of entries from a directory. + * + * @param {Function} successCallback is called with a list of entries + * @param {Function} errorCallback is called with a FileError + */ +DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) { + // If we've already read and passed on this directory's entries, return an empty list. + if (this.hasReadEntries) { + successCallback([]); + return; + } + var reader = this; + var win = typeof successCallback !== 'function' ? null : function(result) { + var retVal = []; + for (var i=0; i or + *