cleanup repository before import
This commit is contained in:
parent
da0c687131
commit
6f4758839b
178 changed files with 0 additions and 35803 deletions
|
@ -1,32 +0,0 @@
|
|||
SJCL used to be in the public domain. Now it's:
|
||||
|
||||
Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh, Stanford University.
|
||||
|
||||
This is for liability reasons. (Speaking of which, SJCL comes with NO
|
||||
WARRANTY WHATSOEVER, express or implied, to the limit of applicable
|
||||
law.)
|
||||
|
||||
SJCL is dual-licensed under the GNU GPL version 2.0 or higher, and a
|
||||
2-clause BSD license. You may use SJCL under the terms of either of
|
||||
these licenses. For your convenience, the GPL versions 2.0 and 3.0
|
||||
and the 2-clause BSD license are included here. Additionally, you may
|
||||
serve "crunched" copies of sjcl (i.e. those with comments removed,
|
||||
and other transformations to reduce code size) without any copyright
|
||||
notice.
|
||||
|
||||
SJCL includes JsDoc toolkit, YUI compressor, Closure compressor,
|
||||
JSLint and the CodeView template in its build system. These programs'
|
||||
copyrights are owned by other people. They are distributed here under
|
||||
the MPL, MIT, BSD, Apache and JSLint licenses. Codeview is "free for
|
||||
download" but has no license attached; it is Copyright 2010 Wouter Bos.
|
||||
|
||||
The BSD license is (almost?) strictly more permissive, but the
|
||||
additionally licensing under the GPL allows us to use OCB 2.0 code
|
||||
royalty-free (at least, if OCB 2.0's creator Phil Rogaway has anything
|
||||
to say about it). Note that if you redistribute SJCL under a license
|
||||
other than the GPL, you or your users may need to pay patent licensing
|
||||
fees for OCB 2.0.
|
||||
|
||||
There may be patents which apply to SJCL other than Phil Rogaway's OCB
|
||||
patents. We suggest that you consult legal counsel before using SJCL
|
||||
in a commercial project.
|
|
@ -1,36 +0,0 @@
|
|||
SJCL comes with a file sjcl.js pre-built. This default build includes
|
||||
all the modules except for sjcl.codec.bytes (because the demo site doesn't
|
||||
use it). All you need to do to install is copy this file to your web
|
||||
server and start using it.
|
||||
|
||||
SJCL is divided into modules implementing various cryptographic and
|
||||
convenience functions. If you don't need them all for your application,
|
||||
you can reconfigure SJCL for a smaller code size. To do this, you can
|
||||
run
|
||||
|
||||
./configure --without-all --with-aes --with-sha256 ...
|
||||
|
||||
Then type
|
||||
|
||||
make
|
||||
|
||||
to rebuild sjcl.js. This will also create a few intermediate files
|
||||
core*.js; you can delete these automatically by typing
|
||||
|
||||
make sjcl.js tidy
|
||||
|
||||
instead. You will need make, perl, bash and java to rebuild SJCL.
|
||||
|
||||
Some of the modules depend on other modules; configure should handle this
|
||||
automatically unless you tell it --without-FOO --with-BAR, where BAR
|
||||
depends on FOO. If you do this, configure will yell at you.
|
||||
|
||||
SJCL is compressed by stripping comments, shortening variable names, etc.
|
||||
You can also pass a --compress argument to configure to change the
|
||||
compressor. By default SJCL uses some perl/sh scripts and Google's
|
||||
Closure compressor.
|
||||
|
||||
If you reconfigure SJCL, it is recommended that you run the included test
|
||||
suite by typing "make test". If this prints "FAIL" or segfaults, SJCL
|
||||
doesn't work; please file a bug.
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation
|
||||
are those of the authors and should not be interpreted as representing
|
||||
official policies, either expressed or implied, of the authors.
|
|
@ -1,339 +0,0 @@
|
|||
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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
|
@ -1,674 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
@ -1,16 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>SJCL browser test</title>
|
||||
<link rel="stylesheet" type="text/css" href="test.css"/>
|
||||
<script type="text/javascript" src="browserUtil.js"></script>
|
||||
<script type="text/javascript" src="../test/run_tests_browser.js"></script>
|
||||
</head>
|
||||
<body onload="testCores(['sjcl.js'])">
|
||||
<h1>SJCL browser test</h1>
|
||||
<div id="status">Waiting for tests to begin...</div>
|
||||
<div id="print"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,133 +0,0 @@
|
|||
browserUtil = {};
|
||||
|
||||
browserUtil.isRhino = (typeof(window) === 'undefined');
|
||||
|
||||
/**
|
||||
* Pause (for the graphics to update and the script timer to clear), then run the
|
||||
* specified action.
|
||||
*/
|
||||
browserUtil.pauseAndThen = function (cb) {
|
||||
cb && window.setTimeout(cb, 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate using continuation-passing style.
|
||||
*/
|
||||
browserUtil.cpsIterate = function (f, start, end, pause, callback) {
|
||||
var pat = pause ? browserUtil.pauseAndThen : function (cb) { cb && cb(); };
|
||||
function go() {
|
||||
var called = false;
|
||||
if (start >= end) {
|
||||
pat(callback);
|
||||
} else {
|
||||
pat(function () { f(start, function () {
|
||||
if (!called) { called = true; start++; go(); }
|
||||
}); });
|
||||
}
|
||||
}
|
||||
go (start);
|
||||
};
|
||||
|
||||
/**
|
||||
* Map a function over an array using continuation-passing style.
|
||||
*/
|
||||
browserUtil.cpsMap = function (map, list, pause, callback) {
|
||||
browserUtil.cpsIterate(function (i, cb) { map(list[i], i, list.length, cb); },
|
||||
0, list.length, pause, callback);
|
||||
}
|
||||
|
||||
/** Cache for remotely loaded scripts. */
|
||||
browserUtil.scriptCache = {}
|
||||
|
||||
/** Load several scripts, then call back */
|
||||
browserUtil.loadScripts = function(scriptNames, cbSuccess, cbError) {
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
browserUtil.cpsMap(function (script, i, n, cb) {
|
||||
var scriptE = document.createElement('script'), xhr, loaded = false;
|
||||
|
||||
browserUtil.status("Loading script " + script);
|
||||
|
||||
if (window.location.protocol === "file:") {
|
||||
/* Can't make an AJAX request for files.
|
||||
* But, we know the load time will be short, so timeout-based error
|
||||
* detection is fine.
|
||||
*/
|
||||
scriptE.onload = function () {
|
||||
loaded = true;
|
||||
cb();
|
||||
};
|
||||
scriptE.onerror = function(err) {
|
||||
cbError && cbError(script, err, cb);
|
||||
};
|
||||
script.onreadystatechange = function() {
|
||||
if (this.readyState == 'complete' || this.readyState == 'loaded') {
|
||||
loaded = true;
|
||||
cb();
|
||||
}
|
||||
};
|
||||
scriptE.type = 'text/javascript';
|
||||
scriptE.src = script+"?"+(new Date().valueOf());
|
||||
window.setTimeout(function () {
|
||||
loaded || cbError && cbError(script, "timeout expired", cb);
|
||||
}, 100);
|
||||
head.appendChild(scriptE);
|
||||
} else if (browserUtil.scriptCache[script] !== undefined) {
|
||||
try {
|
||||
scriptE.appendChild(document.createTextNode(browserUtil.scriptCache[script]));
|
||||
} catch (e) {
|
||||
scriptE.text = browserUtil.scriptCache[script];
|
||||
}
|
||||
head.appendChild(scriptE);
|
||||
cb();
|
||||
} else {
|
||||
var xhr;
|
||||
if (window.XMLHttpRequest) {
|
||||
xhr = new XMLHttpRequest;
|
||||
} else if (window.ActiveXObject) {
|
||||
xhr = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
browserUtil.scriptCache[script] = xhr.responseText;
|
||||
try {
|
||||
scriptE.appendChild(document.createTextNode(xhr.responseText));
|
||||
} catch (e) {
|
||||
scriptE.text = xhr.responseText;
|
||||
}
|
||||
head.appendChild(scriptE);
|
||||
cb();
|
||||
} else {
|
||||
cbError && cbError(script, xhr.status, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.open("GET", script+"?"+(new Date().valueOf()), true);
|
||||
xhr.send();
|
||||
}
|
||||
}, scriptNames, false, cbSuccess);
|
||||
};
|
||||
|
||||
/** Write a message to the console */
|
||||
browserUtil.write = function(type, message) {
|
||||
var d1 = document.getElementById("print"), d2 = document.createElement("div"), d3 = document.createElement("div");
|
||||
d3.className = type;
|
||||
d3.appendChild(document.createTextNode(message));
|
||||
d2.appendChild(d3);
|
||||
d1.appendChild(d2);
|
||||
return { update: function (type2, message2) {
|
||||
var d4 = document.createElement("div");
|
||||
d4.className = type2 + " also";
|
||||
d4.appendChild(document.createTextNode(message2));
|
||||
d2.insertBefore(d4, d3);
|
||||
}};
|
||||
};
|
||||
|
||||
/** Write a newline. Does nothing in the browser. */
|
||||
browserUtil.writeNewline = function () { };
|
||||
|
||||
/** Write a message to the status line */
|
||||
browserUtil.status = function(message) {
|
||||
var d1 = document.getElementById("status");
|
||||
d1.replaceChild(document.createTextNode(message), d1.firstChild);
|
||||
};
|
|
@ -1,44 +0,0 @@
|
|||
browserUtil = {
|
||||
isRhino: true,
|
||||
|
||||
pauseAndThen: function (cb) { cb(); },
|
||||
|
||||
cpsIterate: function (f, start, end, pause, callback) {
|
||||
function go() {
|
||||
var called = false;
|
||||
if (start >= end) {
|
||||
callback && callback();
|
||||
} else {
|
||||
f(start, function () {
|
||||
if (!called) { called = true; start++; go(); }
|
||||
});
|
||||
}
|
||||
}
|
||||
go (start);
|
||||
},
|
||||
|
||||
cpsMap: function (map, list, pause, callback) {
|
||||
browserUtil.cpsIterate(function (i, cb) { map(list[i], i, list.length, cb); },
|
||||
0, list.length, pause, callback);
|
||||
},
|
||||
|
||||
loadScripts: function(scriptNames, callback) {
|
||||
for (i=0; i<scriptNames.length; i++) {
|
||||
load(scriptNames[i]);
|
||||
callback && callback();
|
||||
}
|
||||
},
|
||||
|
||||
write: function(type, message) {
|
||||
print(message);
|
||||
return { update: function (type2, message2) {
|
||||
if (type2 === 'pass') { print(" + " + message2); }
|
||||
else if (type2 === 'unimplemented') { print(" ? " + message2); }
|
||||
else { print(" - " + message2); }
|
||||
}};
|
||||
},
|
||||
|
||||
writeNewline: function () { print(""); },
|
||||
|
||||
status: function(message) {}
|
||||
};
|
|
@ -1,59 +0,0 @@
|
|||
* {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
font-family: Arial, Helvetica, FreeSans, sans;
|
||||
}
|
||||
|
||||
#print {
|
||||
position: relative;
|
||||
width: 40em;
|
||||
margin: 0px auto;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#print div {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pass { color: #0A0; }
|
||||
.fail { color: #A00; }
|
||||
.unimplemented { color: #F80; }
|
||||
|
||||
.begin {
|
||||
text-align: center;
|
||||
padding-bottom: 2px;
|
||||
border-bottom: 1px solid #aaa;
|
||||
margin: 0px auto 2px auto;
|
||||
}
|
||||
|
||||
.all {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
*+* > .begin, *+* > .all {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.also {
|
||||
float: right;
|
||||
width: 17em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
background: #8A0000;
|
||||
padding: 5px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#status {
|
||||
padding: 3px 10px 3px 5px;
|
||||
background: #d5c490;
|
||||
color: #444;
|
||||
font-size: 0.8em;
|
||||
margin-bottom: 1em;
|
||||
height: 1.3em;
|
||||
vertical-align: middle;
|
||||
}
|
Binary file not shown.
|
@ -1,15 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
DIR=`dirname $0`
|
||||
|
||||
$DIR/remove_constants.pl $1 | $DIR/opacify.pl > ._tmpRC.js
|
||||
|
||||
echo -n '"use strict";'
|
||||
java -jar $DIR/compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS \
|
||||
--js ._tmpRC.js \
|
||||
| $DIR/digitize.pl \
|
||||
| $DIR/dewindowize.pl
|
||||
|
||||
|
||||
rm -f ._tmpRC.js
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Compress $1 with YUI Compressor 2.4.2, returning the compressed script on stdout
|
||||
|
||||
DIR=`dirname $0`
|
||||
|
||||
$DIR/remove_constants.pl $1 > ._tmpRC.js
|
||||
|
||||
java -jar $DIR/yuicompressor-2.4.2.jar ._tmpRC.js \
|
||||
| $DIR/digitize.pl
|
||||
|
||||
rm -f ._tmpRC.js
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
while (<>) {
|
||||
s/window\.sjcl\s*=/var sjcl=/g;
|
||||
s/window\.sjcl/sjcl/g;
|
||||
print;
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
# Convert numbers to hex, when doing so is likely to increase compressibility.
|
||||
# This actually makes the script slightly longer, but generally makes it compress
|
||||
# to something shorter.
|
||||
#
|
||||
# Here we're targeting constants like 0xFF, 0xFFFF0000, 0x10101, 0x100000000, etc.
|
||||
|
||||
sub digitize {
|
||||
my $number = shift;
|
||||
if ($number >= 256) {
|
||||
my $nn = `printf "%x" $number`;
|
||||
if ($nn =~ /^[01f]+$/i) { return "0x$nn"; }
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
while (<>) {
|
||||
s/([^a-zA-Z0-9_])(\d+)/$1 . digitize $2/eg;
|
||||
print;
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
# This script is a hack.
|
||||
#
|
||||
# Opacify all non-private names by turning them into strings.
|
||||
# That way, the Google compressor won't rename them.
|
||||
#
|
||||
# The script ignores properties whose names begin with _, because they
|
||||
# are believed to be private.
|
||||
#
|
||||
# XXX TODO FIXME: this messes with strings, so it screws up exceptions.
|
||||
|
||||
my $script = join '', <>;
|
||||
|
||||
# remove comments
|
||||
$script =~ s=/\*([^\*]|\*+[^\/])*\*/==g;
|
||||
$script =~ s=//.*==g;
|
||||
|
||||
# stringify property names
|
||||
$script =~ s=\.([a-zA-Z][_a-zA-Z0-9]*)=['$1']=g;
|
||||
|
||||
# stringify sjcl
|
||||
$script =~ s=(?:var\s+)?sjcl(\.|\s*\=)=window['sjcl']$1=g;
|
||||
|
||||
# stringify object notation
|
||||
$script =~ s=([\{,]\s*)([a-zA-Z0-9][_a-zA-Z0-9]*):=$1'$2':=g;
|
||||
|
||||
# Export sjcl. This is a bit of a hack, and might get replaced later.
|
||||
print $script;
|
||||
|
||||
# not necessary with windowization.
|
||||
# print "window\['sjcl'\] = sjcl;\n";
|
|
@ -1,69 +0,0 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
# This script is a hack. It identifies things which it believes to be
|
||||
# constant, then replaces them throughout the code.
|
||||
#
|
||||
# Constants are identified as properties declared in object notation
|
||||
# with values consisting only of capital letters and underscores. If
|
||||
# the first character is an underscore, the constant is private, and
|
||||
# can be removed entirely.
|
||||
#
|
||||
# The script dies if any two constants have the same property name but
|
||||
# different values.
|
||||
my $script = join '', <>;
|
||||
|
||||
# remove comments
|
||||
$script =~ s=/\*([^\*]|\*+[^\/])*\*/==g;
|
||||
$script =~ s=//.*==g;
|
||||
|
||||
sub preserve {
|
||||
my $stuff = shift;
|
||||
$stuff =~ s/,//;
|
||||
return $stuff;
|
||||
}
|
||||
|
||||
my %constants = ();
|
||||
|
||||
sub add_constant {
|
||||
my ($name, $value) = @_;
|
||||
if (defined $constants{$name} && $constants{$name} ne $value) {
|
||||
print STDERR "variant constant $name = $value";
|
||||
die;
|
||||
} else {
|
||||
$constants{$name} = $value;
|
||||
#print STDERR "constant: $name = $value\n";
|
||||
}
|
||||
}
|
||||
|
||||
# find private constants
|
||||
while ($script =~
|
||||
s/([,\{]) \s* # indicator that this is part of an object
|
||||
(_[A-Z0-9_]+) \s* : \s* # all-caps variable name beginning with _
|
||||
(\d+|0x[0-9A-Fa-f]+) \s* # numeric value
|
||||
([,\}]) # next part of object
|
||||
/preserve "$1$4"/ex) {
|
||||
add_constant $2, $3;
|
||||
}
|
||||
|
||||
my $script2 = '';
|
||||
|
||||
# find public constants
|
||||
while ($script =~
|
||||
s/^(.*?) # beginning of script
|
||||
([,\{]) \s* # indicator that this is part of an object
|
||||
([A-Z0-9_]+) \s* : \s* # all-caps variable name
|
||||
(\d+|0x[0-9A-Fa-f]+) \s* # numeric value
|
||||
([,\}]) # next part of object([,\{]) \s*
|
||||
/$5/esx) {
|
||||
$script2 .= "$1$2$3:$4";
|
||||
add_constant $3, $4;
|
||||
}
|
||||
|
||||
$script = "$script2$script";
|
||||
|
||||
foreach (keys %constants) {
|
||||
my $value = $constants{$_};
|
||||
$script =~ s/(?:[a-zA-Z0-9_]+\.)+$_(?=[^a-zA-Z0-9_])/$value/g;
|
||||
}
|
||||
|
||||
print $script;
|
Binary file not shown.
208
core/aes.js
208
core/aes.js
|
@ -1,208 +0,0 @@
|
|||
/** @fileOverview Low-level AES implementation.
|
||||
*
|
||||
* This file contains a low-level implementation of AES, optimized for
|
||||
* size and for efficiency on several browsers. It is based on
|
||||
* OpenSSL's aes_core.c, a public-domain implementation by Vincent
|
||||
* Rijmen, Antoon Bosselaers and Paulo Barreto.
|
||||
*
|
||||
* An older version of this implementation is available in the public
|
||||
* domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
|
||||
* Stanford University 2008-2010 and BSD-licensed for liability
|
||||
* reasons.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Schedule out an AES key for both encryption and decryption. This
|
||||
* is a low-level class. Use a cipher mode to do bulk encryption.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Array} key The key as an array of 4, 6 or 8 words.
|
||||
*
|
||||
* @class Advanced Encryption Standard (low-level interface)
|
||||
*/
|
||||
sjcl.cipher.aes = function (key) {
|
||||
if (!this._tables[0][0][0]) {
|
||||
this._precompute();
|
||||
}
|
||||
|
||||
var i, j, tmp,
|
||||
encKey, decKey,
|
||||
sbox = this._tables[0][4], decTable = this._tables[1],
|
||||
keyLen = key.length, rcon = 1;
|
||||
|
||||
if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
|
||||
throw new sjcl.exception.invalid("invalid aes key size");
|
||||
}
|
||||
|
||||
this._key = [encKey = key.slice(0), decKey = []];
|
||||
|
||||
// schedule encryption keys
|
||||
for (i = keyLen; i < 4 * keyLen + 28; i++) {
|
||||
tmp = encKey[i-1];
|
||||
|
||||
// apply sbox
|
||||
if (i%keyLen === 0 || (keyLen === 8 && i%keyLen === 4)) {
|
||||
tmp = sbox[tmp>>>24]<<24 ^ sbox[tmp>>16&255]<<16 ^ sbox[tmp>>8&255]<<8 ^ sbox[tmp&255];
|
||||
|
||||
// shift rows and add rcon
|
||||
if (i%keyLen === 0) {
|
||||
tmp = tmp<<8 ^ tmp>>>24 ^ rcon<<24;
|
||||
rcon = rcon<<1 ^ (rcon>>7)*283;
|
||||
}
|
||||
}
|
||||
|
||||
encKey[i] = encKey[i-keyLen] ^ tmp;
|
||||
}
|
||||
|
||||
// schedule decryption keys
|
||||
for (j = 0; i; j++, i--) {
|
||||
tmp = encKey[j&3 ? i : i - 4];
|
||||
if (i<=4 || j<4) {
|
||||
decKey[j] = tmp;
|
||||
} else {
|
||||
decKey[j] = decTable[0][sbox[tmp>>>24 ]] ^
|
||||
decTable[1][sbox[tmp>>16 & 255]] ^
|
||||
decTable[2][sbox[tmp>>8 & 255]] ^
|
||||
decTable[3][sbox[tmp & 255]];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.cipher.aes.prototype = {
|
||||
// public
|
||||
/* Something like this might appear here eventually
|
||||
name: "AES",
|
||||
blockSize: 4,
|
||||
keySizes: [4,6,8],
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encrypt an array of 4 big-endian words.
|
||||
* @param {Array} data The plaintext.
|
||||
* @return {Array} The ciphertext.
|
||||
*/
|
||||
encrypt:function (data) { return this._crypt(data,0); },
|
||||
|
||||
/**
|
||||
* Decrypt an array of 4 big-endian words.
|
||||
* @param {Array} data The ciphertext.
|
||||
* @return {Array} The plaintext.
|
||||
*/
|
||||
decrypt:function (data) { return this._crypt(data,1); },
|
||||
|
||||
/**
|
||||
* The expanded S-box and inverse S-box tables. These will be computed
|
||||
* on the client so that we don't have to send them down the wire.
|
||||
*
|
||||
* There are two tables, _tables[0] is for encryption and
|
||||
* _tables[1] is for decryption.
|
||||
*
|
||||
* The first 4 sub-tables are the expanded S-box with MixColumns. The
|
||||
* last (_tables[01][4]) is the S-box itself.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_tables: [[[],[],[],[],[]],[[],[],[],[],[]]],
|
||||
|
||||
/**
|
||||
* Expand the S-box tables.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_precompute: function () {
|
||||
var encTable = this._tables[0], decTable = this._tables[1],
|
||||
sbox = encTable[4], sboxInv = decTable[4],
|
||||
i, x, xInv, d=[], th=[], x2, x4, x8, s, tEnc, tDec;
|
||||
|
||||
// Compute double and third tables
|
||||
for (i = 0; i < 256; i++) {
|
||||
th[( d[i] = i<<1 ^ (i>>7)*283 )^i]=i;
|
||||
}
|
||||
|
||||
for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
|
||||
// Compute sbox
|
||||
s = xInv ^ xInv<<1 ^ xInv<<2 ^ xInv<<3 ^ xInv<<4;
|
||||
s = s>>8 ^ s&255 ^ 99;
|
||||
sbox[x] = s;
|
||||
sboxInv[s] = x;
|
||||
|
||||
// Compute MixColumns
|
||||
x8 = d[x4 = d[x2 = d[x]]];
|
||||
tDec = x8*0x1010101 ^ x4*0x10001 ^ x2*0x101 ^ x*0x1010100;
|
||||
tEnc = d[s]*0x101 ^ s*0x1010100;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
encTable[i][x] = tEnc = tEnc<<24 ^ tEnc>>>8;
|
||||
decTable[i][s] = tDec = tDec<<24 ^ tDec>>>8;
|
||||
}
|
||||
}
|
||||
|
||||
// Compactify. Considerable speedup on Firefox.
|
||||
for (i = 0; i < 5; i++) {
|
||||
encTable[i] = encTable[i].slice(0);
|
||||
decTable[i] = decTable[i].slice(0);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Encryption and decryption core.
|
||||
* @param {Array} input Four words to be encrypted or decrypted.
|
||||
* @param dir The direction, 0 for encrypt and 1 for decrypt.
|
||||
* @return {Array} The four encrypted or decrypted words.
|
||||
* @private
|
||||
*/
|
||||
_crypt:function (input, dir) {
|
||||
if (input.length !== 4) {
|
||||
throw new sjcl.exception.invalid("invalid aes block size");
|
||||
}
|
||||
|
||||
var key = this._key[dir],
|
||||
// state variables a,b,c,d are loaded with pre-whitened data
|
||||
a = input[0] ^ key[0],
|
||||
b = input[dir ? 3 : 1] ^ key[1],
|
||||
c = input[2] ^ key[2],
|
||||
d = input[dir ? 1 : 3] ^ key[3],
|
||||
a2, b2, c2,
|
||||
|
||||
nInnerRounds = key.length/4 - 2,
|
||||
i,
|
||||
kIndex = 4,
|
||||
out = [0,0,0,0],
|
||||
table = this._tables[dir],
|
||||
|
||||
// load up the tables
|
||||
t0 = table[0],
|
||||
t1 = table[1],
|
||||
t2 = table[2],
|
||||
t3 = table[3],
|
||||
sbox = table[4];
|
||||
|
||||
// Inner rounds. Cribbed from OpenSSL.
|
||||
for (i = 0; i < nInnerRounds; i++) {
|
||||
a2 = t0[a>>>24] ^ t1[b>>16 & 255] ^ t2[c>>8 & 255] ^ t3[d & 255] ^ key[kIndex];
|
||||
b2 = t0[b>>>24] ^ t1[c>>16 & 255] ^ t2[d>>8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
|
||||
c2 = t0[c>>>24] ^ t1[d>>16 & 255] ^ t2[a>>8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
|
||||
d = t0[d>>>24] ^ t1[a>>16 & 255] ^ t2[b>>8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
|
||||
kIndex += 4;
|
||||
a=a2; b=b2; c=c2;
|
||||
}
|
||||
|
||||
// Last round.
|
||||
for (i = 0; i < 4; i++) {
|
||||
out[dir ? 3&-i : i] =
|
||||
sbox[a>>>24 ]<<24 ^
|
||||
sbox[b>>16 & 255]<<16 ^
|
||||
sbox[c>>8 & 255]<<8 ^
|
||||
sbox[d & 255] ^
|
||||
key[kIndex++];
|
||||
a2=a; a=b; b=c; c=d; d=a2;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
187
core/bitArray.js
187
core/bitArray.js
|
@ -1,187 +0,0 @@
|
|||
/** @fileOverview Arrays of bits, encoded as arrays of Numbers.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Arrays of bits, encoded as arrays of Numbers.
|
||||
*
|
||||
* @description
|
||||
* <p>
|
||||
* These objects are the currency accepted by SJCL's crypto functions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Most of our crypto primitives operate on arrays of 4-byte words internally,
|
||||
* but many of them can take arguments that are not a multiple of 4 bytes.
|
||||
* This library encodes arrays of bits (whose size need not be a multiple of 8
|
||||
* bits) as arrays of 32-bit words. The bits are packed, big-endian, into an
|
||||
* array of words, 32 bits at a time. Since the words are double-precision
|
||||
* floating point numbers, they fit some extra data. We use this (in a private,
|
||||
* possibly-changing manner) to encode the number of bits actually present
|
||||
* in the last word of the array.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Because bitwise ops clear this out-of-band data, these arrays can be passed
|
||||
* to ciphers like AES which want arrays of words.
|
||||
* </p>
|
||||
*/
|
||||
sjcl.bitArray = {
|
||||
/**
|
||||
* Array slices in units of bits.
|
||||
* @param {bitArray} a The array to slice.
|
||||
* @param {Number} bstart The offset to the start of the slice, in bits.
|
||||
* @param {Number} bend The offset to the end of the slice, in bits. If this is undefined,
|
||||
* slice until the end of the array.
|
||||
* @return {bitArray} The requested slice.
|
||||
*/
|
||||
bitSlice: function (a, bstart, bend) {
|
||||
a = sjcl.bitArray._shiftRight(a.slice(bstart/32), 32 - (bstart & 31)).slice(1);
|
||||
return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend-bstart);
|
||||
},
|
||||
|
||||
/**
|
||||
* Extract a number packed into a bit array.
|
||||
* @param {bitArray} a The array to slice.
|
||||
* @param {Number} bstart The offset to the start of the slice, in bits.
|
||||
* @param {Number} length The length of the number to extract.
|
||||
* @return {Number} The requested slice.
|
||||
*/
|
||||
extract: function(a, bstart, blength) {
|
||||
// FIXME: this Math.floor is not necessary at all, but for some reason
|
||||
// seems to suppress a bug in the Chromium JIT.
|
||||
var x, sh = Math.floor((-bstart-blength) & 31);
|
||||
if ((bstart + blength - 1 ^ bstart) & -32) {
|
||||
// it crosses a boundary
|
||||
x = (a[bstart/32|0] << (32 - sh)) ^ (a[bstart/32+1|0] >>> sh);
|
||||
} else {
|
||||
// within a single word
|
||||
x = a[bstart/32|0] >>> sh;
|
||||
}
|
||||
return x & ((1<<blength) - 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Concatenate two bit arrays.
|
||||
* @param {bitArray} a1 The first array.
|
||||
* @param {bitArray} a2 The second array.
|
||||
* @return {bitArray} The concatenation of a1 and a2.
|
||||
*/
|
||||
concat: function (a1, a2) {
|
||||
if (a1.length === 0 || a2.length === 0) {
|
||||
return a1.concat(a2);
|
||||
}
|
||||
|
||||
var out, i, last = a1[a1.length-1], shift = sjcl.bitArray.getPartial(last);
|
||||
if (shift === 32) {
|
||||
return a1.concat(a2);
|
||||
} else {
|
||||
return sjcl.bitArray._shiftRight(a2, shift, last|0, a1.slice(0,a1.length-1));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the length of an array of bits.
|
||||
* @param {bitArray} a The array.
|
||||
* @return {Number} The length of a, in bits.
|
||||
*/
|
||||
bitLength: function (a) {
|
||||
var l = a.length, x;
|
||||
if (l === 0) { return 0; }
|
||||
x = a[l - 1];
|
||||
return (l-1) * 32 + sjcl.bitArray.getPartial(x);
|
||||
},
|
||||
|
||||
/**
|
||||
* Truncate an array.
|
||||
* @param {bitArray} a The array.
|
||||
* @param {Number} len The length to truncate to, in bits.
|
||||
* @return {bitArray} A new array, truncated to len bits.
|
||||
*/
|
||||
clamp: function (a, len) {
|
||||
if (a.length * 32 < len) { return a; }
|
||||
a = a.slice(0, Math.ceil(len / 32));
|
||||
var l = a.length;
|
||||
len = len & 31;
|
||||
if (l > 0 && len) {
|
||||
a[l-1] = sjcl.bitArray.partial(len, a[l-1] & 0x80000000 >> (len-1), 1);
|
||||
}
|
||||
return a;
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a partial word for a bit array.
|
||||
* @param {Number} len The number of bits in the word.
|
||||
* @param {Number} x The bits.
|
||||
* @param {Number} [0] _end Pass 1 if x has already been shifted to the high side.
|
||||
* @return {Number} The partial word.
|
||||
*/
|
||||
partial: function (len, x, _end) {
|
||||
if (len === 32) { return x; }
|
||||
return (_end ? x|0 : x << (32-len)) + len * 0x10000000000;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the number of bits used by a partial word.
|
||||
* @param {Number} x The partial word.
|
||||
* @return {Number} The number of bits used by the partial word.
|
||||
*/
|
||||
getPartial: function (x) {
|
||||
return Math.round(x/0x10000000000) || 32;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compare two arrays for equality in a predictable amount of time.
|
||||
* @param {bitArray} a The first array.
|
||||
* @param {bitArray} b The second array.
|
||||
* @return {boolean} true if a == b; false otherwise.
|
||||
*/
|
||||
equal: function (a, b) {
|
||||
if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) {
|
||||
return false;
|
||||
}
|
||||
var x = 0, i;
|
||||
for (i=0; i<a.length; i++) {
|
||||
x |= a[i]^b[i];
|
||||
}
|
||||
return (x === 0);
|
||||
},
|
||||
|
||||
/** Shift an array right.
|
||||
* @param {bitArray} a The array to shift.
|
||||
* @param {Number} shift The number of bits to shift.
|
||||
* @param {Number} [carry=0] A byte to carry in
|
||||
* @param {bitArray} [out=[]] An array to prepend to the output.
|
||||
* @private
|
||||
*/
|
||||
_shiftRight: function (a, shift, carry, out) {
|
||||
var i, last2=0, shift2;
|
||||
if (out === undefined) { out = []; }
|
||||
|
||||
for (; shift >= 32; shift -= 32) {
|
||||
out.push(carry);
|
||||
carry = 0;
|
||||
}
|
||||
if (shift === 0) {
|
||||
return out.concat(a);
|
||||
}
|
||||
|
||||
for (i=0; i<a.length; i++) {
|
||||
out.push(carry | a[i]>>>shift);
|
||||
carry = a[i] << (32-shift);
|
||||
}
|
||||
last2 = a.length ? a[a.length-1] : 0;
|
||||
shift2 = sjcl.bitArray.getPartial(last2);
|
||||
out.push(sjcl.bitArray.partial(shift+shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(),1));
|
||||
return out;
|
||||
},
|
||||
|
||||
/** xor a block of 4 words together.
|
||||
* @private
|
||||
*/
|
||||
_xor4: function(x,y) {
|
||||
return [x[0]^y[0],x[1]^y[1],x[2]^y[2],x[3]^y[3]];
|
||||
}
|
||||
};
|
534
core/bn.js
534
core/bn.js
|
@ -1,534 +0,0 @@
|
|||
/**
|
||||
* Constructs a new bignum from another bignum, a number or a hex string.
|
||||
*/
|
||||
sjcl.bn = function(it) {
|
||||
this.initWith(it);
|
||||
};
|
||||
|
||||
sjcl.bn.prototype = {
|
||||
radix: 24,
|
||||
maxMul: 8,
|
||||
_class: sjcl.bn,
|
||||
|
||||
copy: function() {
|
||||
return new this._class(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes this with it, either as a bn, a number, or a hex string.
|
||||
*/
|
||||
initWith: function(it) {
|
||||
var i=0, k, n, l;
|
||||
switch(typeof it) {
|
||||
case "object":
|
||||
this.limbs = it.limbs.slice(0);
|
||||
break;
|
||||
|
||||
case "number":
|
||||
this.limbs = [it];
|
||||
this.normalize();
|
||||
break;
|
||||
|
||||
case "string":
|
||||
it = it.replace(/^0x/, '');
|
||||
this.limbs = [];
|
||||
// hack
|
||||
k = this.radix / 4;
|
||||
for (i=0; i < it.length; i+=k) {
|
||||
this.limbs.push(parseInt(it.substring(Math.max(it.length - i - k, 0), it.length - i),16));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
this.limbs = [0];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if "this" and "that" are equal. Calls fullReduce().
|
||||
* Equality test is in constant time.
|
||||
*/
|
||||
equals: function(that) {
|
||||
if (typeof that === "number") { that = new this._class(that); }
|
||||
var difference = 0, i;
|
||||
this.fullReduce();
|
||||
that.fullReduce();
|
||||
for (i = 0; i < this.limbs.length || i < that.limbs.length; i++) {
|
||||
difference |= this.getLimb(i) ^ that.getLimb(i);
|
||||
}
|
||||
return (difference === 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the i'th limb of this, zero if i is too large.
|
||||
*/
|
||||
getLimb: function(i) {
|
||||
return (i >= this.limbs.length) ? 0 : this.limbs[i];
|
||||
},
|
||||
|
||||
/**
|
||||
* Constant time comparison function.
|
||||
* Returns 1 if this >= that, or zero otherwise.
|
||||
*/
|
||||
greaterEquals: function(that) {
|
||||
if (typeof that === "number") { that = new this._class(that); }
|
||||
var less = 0, greater = 0, i, a, b;
|
||||
i = Math.max(this.limbs.length, that.limbs.length) - 1;
|
||||
for (; i>= 0; i--) {
|
||||
a = this.getLimb(i);
|
||||
b = that.getLimb(i);
|
||||
greater |= (b - a) & ~less;
|
||||
less |= (a - b) & ~greater;
|
||||
}
|
||||
return (greater | ~less) >>> 31;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert to a hex string.
|
||||
*/
|
||||
toString: function() {
|
||||
this.fullReduce();
|
||||
var out="", i, s, l = this.limbs;
|
||||
for (i=0; i < this.limbs.length; i++) {
|
||||
s = l[i].toString(16);
|
||||
while (i < this.limbs.length - 1 && s.length < 6) {
|
||||
s = "0" + s;
|
||||
}
|
||||
out = s + out;
|
||||
}
|
||||
return "0x"+out;
|
||||
},
|
||||
|
||||
/** this += that. Does not normalize. */
|
||||
addM: function(that) {
|
||||
if (typeof(that) !== "object") { that = new this._class(that); }
|
||||
var i, l=this.limbs, ll=that.limbs;
|
||||
for (i=l.length; i<ll.length; i++) {
|
||||
l[i] = 0;
|
||||
}
|
||||
for (i=0; i<ll.length; i++) {
|
||||
l[i] += ll[i];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/** this *= 2. Requires normalized; ends up normalized. */
|
||||
doubleM: function() {
|
||||
var i, carry=0, tmp, r=this.radix, m=this.radixMask, l=this.limbs;
|
||||
for (i=0; i<l.length; i++) {
|
||||
tmp = l[i];
|
||||
tmp = tmp+tmp+carry;
|
||||
l[i] = tmp & m;
|
||||
carry = tmp >> r;
|
||||
}
|
||||
if (carry) {
|
||||
l.push(carry);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/** this /= 2, rounded down. Requires normalized; ends up normalized. */
|
||||
halveM: function() {
|
||||
var i, carry=0, tmp, r=this.radix, l=this.limbs;
|
||||
for (i=l.length-1; i>=0; i--) {
|
||||
tmp = l[i];
|
||||
l[i] = (tmp+carry)>>1;
|
||||
carry = (tmp&1) << r;
|
||||
}
|
||||
if (!l[l.length-1]) {
|
||||
l.pop();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/** this -= that. Does not normalize. */
|
||||
subM: function(that) {
|
||||
if (typeof(that) !== "object") { that = new this._class(that); }
|
||||
var i, l=this.limbs, ll=that.limbs;
|
||||
for (i=l.length; i<ll.length; i++) {
|
||||
l[i] = 0;
|
||||
}
|
||||
for (i=0; i<ll.length; i++) {
|
||||
l[i] -= ll[i];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
mod: function(that) {
|
||||
that = new sjcl.bn(that).normalize(); // copy before we begin
|
||||
var out = new sjcl.bn(this).normalize(), ci=0;
|
||||
|
||||
for (; out.greaterEquals(that); ci++) {
|
||||
that.doubleM();
|
||||
}
|
||||
for (; ci > 0; ci--) {
|
||||
that.halveM();
|
||||
if (out.greaterEquals(that)) {
|
||||
out.subM(that).normalize();
|
||||
}
|
||||
}
|
||||
return out.trim();
|
||||
},
|
||||
|
||||
/** return inverse mod prime p. p must be odd. Binary extended Euclidean algorithm mod p. */
|
||||
inverseMod: function(p) {
|
||||
var a = new sjcl.bn(1), b = new sjcl.bn(0), x = new sjcl.bn(this), y = new sjcl.bn(p), tmp, i, nz=1;
|
||||
|
||||
if (!(p.limbs[0] & 1)) {
|
||||
throw (new sjcl.exception.invalid("inverseMod: p must be odd"));
|
||||
}
|
||||
|
||||
// invariant: y is odd
|
||||
do {
|
||||
if (x.limbs[0] & 1) {
|
||||
if (!x.greaterEquals(y)) {
|
||||
// x < y; swap everything
|
||||
tmp = x; x = y; y = tmp;
|
||||
tmp = a; a = b; b = tmp;
|
||||
}
|
||||
x.subM(y);
|
||||
x.normalize();
|
||||
|
||||
if (!a.greaterEquals(b)) {
|
||||
a.addM(p);
|
||||
}
|
||||
a.subM(b);
|
||||
}
|
||||
|
||||
// cut everything in half
|
||||
x.halveM();
|
||||
if (a.limbs[0] & 1) {
|
||||
a.addM(p);
|
||||
}
|
||||
a.normalize();
|
||||
a.halveM();
|
||||
|
||||
// check for termination: x ?= 0
|
||||
for (i=nz=0; i<x.limbs.length; i++) {
|
||||
nz |= x.limbs[i];
|
||||
}
|
||||
} while(nz);
|
||||
|
||||
if (!y.equals(1)) {
|
||||
throw (new sjcl.exception.invalid("inverseMod: p and x must be relatively prime"));
|
||||
}
|
||||
|
||||
return b;
|
||||
},
|
||||
|
||||
/** this + that. Does not normalize. */
|
||||
add: function(that) {
|
||||
return this.copy().addM(that);
|
||||
},
|
||||
|
||||
/** this - that. Does not normalize. */
|
||||
sub: function(that) {
|
||||
return this.copy().subM(that);
|
||||
},
|
||||
|
||||
/** this * that. Normalizes and reduces. */
|
||||
mul: function(that) {
|
||||
if (typeof(that) === "number") { that = new this._class(that); }
|
||||
var i, j, a = this.limbs, b = that.limbs, al = a.length, bl = b.length, out = new this._class(), c = out.limbs, ai, ii=this.maxMul;
|
||||
|
||||
for (i=0; i < this.limbs.length + that.limbs.length + 1; i++) {
|
||||
c[i] = 0;
|
||||
}
|
||||
for (i=0; i<al; i++) {
|
||||
ai = a[i];
|
||||
for (j=0; j<bl; j++) {
|
||||
c[i+j] += ai * b[j];
|
||||
}
|
||||
|
||||
if (!--ii) {
|
||||
ii = this.maxMul;
|
||||
out.cnormalize();
|
||||
}
|
||||
}
|
||||
return out.cnormalize().reduce();
|
||||
},
|
||||
|
||||
/** this ^ 2. Normalizes and reduces. */
|
||||
square: function() {
|
||||
return this.mul(this);
|
||||
},
|
||||
|
||||
/** this ^ n. Uses square-and-multiply. Normalizes and reduces. */
|
||||
power: function(l) {
|
||||
if (typeof(l) === "number") {
|
||||
l = [l];
|
||||
} else if (l.limbs !== undefined) {
|
||||
l = l.normalize().limbs;
|
||||
}
|
||||
var i, j, out = new this._class(1), pow = this;
|
||||
|
||||
for (i=0; i<l.length; i++) {
|
||||
for (j=0; j<this.radix; j++) {
|
||||
if (l[i] & (1<<j)) {
|
||||
out = out.mul(pow);
|
||||
}
|
||||
pow = pow.square();
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
/** this * that mod N */
|
||||
mulmod: function(that, N) {
|
||||
return this.mod(N).mul(that.mod(N)).mod(N);
|
||||
},
|
||||
|
||||
/** this ^ x mod N */
|
||||
powermod: function(x, N) {
|
||||
var result = new sjcl.bn(1), a = new sjcl.bn(this), k = new sjcl.bn(x);
|
||||
while (true) {
|
||||
if (k.limbs[0] & 1) { result = result.mulmod(a, N); }
|
||||
k.halveM();
|
||||
if (k.equals(0)) { break; }
|
||||
a = a.mulmod(a, N);
|
||||
}
|
||||
return result.normalize().reduce();
|
||||
},
|
||||
|
||||
trim: function() {
|
||||
var l = this.limbs, p;
|
||||
do {
|
||||
p = l.pop();
|
||||
} while (l.length && p === 0);
|
||||
l.push(p);
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Reduce mod a modulus. Stubbed for subclassing. */
|
||||
reduce: function() {
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Reduce and normalize. */
|
||||
fullReduce: function() {
|
||||
return this.normalize();
|
||||
},
|
||||
|
||||
/** Propagate carries. */
|
||||
normalize: function() {
|
||||
var carry=0, i, pv = this.placeVal, ipv = this.ipv, l, m, limbs = this.limbs, ll = limbs.length, mask = this.radixMask;
|
||||
for (i=0; i < ll || (carry !== 0 && carry !== -1); i++) {
|
||||
l = (limbs[i]||0) + carry;
|
||||
m = limbs[i] = l & mask;
|
||||
carry = (l-m)*ipv;
|
||||
}
|
||||
if (carry === -1) {
|
||||
limbs[i-1] -= this.placeVal;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Constant-time normalize. Does not allocate additional space. */
|
||||
cnormalize: function() {
|
||||
var carry=0, i, ipv = this.ipv, l, m, limbs = this.limbs, ll = limbs.length, mask = this.radixMask;
|
||||
for (i=0; i < ll-1; i++) {
|
||||
l = limbs[i] + carry;
|
||||
m = limbs[i] = l & mask;
|
||||
carry = (l-m)*ipv;
|
||||
}
|
||||
limbs[i] += carry;
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Serialize to a bit array */
|
||||
toBits: function(len) {
|
||||
this.fullReduce();
|
||||
len = len || this.exponent || this.limbs.length * this.radix;
|
||||
var i = Math.floor((len-1)/24), w=sjcl.bitArray, e = (len + 7 & -8) % this.radix || this.radix,
|
||||
out = [w.partial(e, this.getLimb(i))];
|
||||
for (i--; i >= 0; i--) {
|
||||
out = w.concat(out, [w.partial(this.radix, this.getLimb(i))]);
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
/** Return the length in bits, rounded up to the nearest byte. */
|
||||
bitLength: function() {
|
||||
this.fullReduce();
|
||||
var out = this.radix * (this.limbs.length - 1),
|
||||
b = this.limbs[this.limbs.length - 1];
|
||||
for (; b; b >>= 1) {
|
||||
out ++;
|
||||
}
|
||||
return out+7 & -8;
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.bn.fromBits = function(bits) {
|
||||
var Class = this, out = new Class(), words=[], w=sjcl.bitArray, t = this.prototype,
|
||||
l = Math.min(this.bitLength || 0x100000000, w.bitLength(bits)), e = l % t.radix || t.radix;
|
||||
|
||||
words[0] = w.extract(bits, 0, e);
|
||||
for (; e < l; e += t.radix) {
|
||||
words.unshift(w.extract(bits, e, t.radix));
|
||||
}
|
||||
|
||||
out.limbs = words;
|
||||
return out;
|
||||
};
|
||||
|
||||
|
||||
|
||||
sjcl.bn.prototype.ipv = 1 / (sjcl.bn.prototype.placeVal = Math.pow(2,sjcl.bn.prototype.radix));
|
||||
sjcl.bn.prototype.radixMask = (1 << sjcl.bn.prototype.radix) - 1;
|
||||
|
||||
/**
|
||||
* Creates a new subclass of bn, based on reduction modulo a pseudo-Mersenne prime,
|
||||
* i.e. a prime of the form 2^e + sum(a * 2^b),where the sum is negative and sparse.
|
||||
*/
|
||||
sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
|
||||
function p(it) {
|
||||
this.initWith(it);
|
||||
/*if (this.limbs[this.modOffset]) {
|
||||
this.reduce();
|
||||
}*/
|
||||
}
|
||||
|
||||
var ppr = p.prototype = new sjcl.bn(), i, tmp, mo;
|
||||
mo = ppr.modOffset = Math.ceil(tmp = exponent / ppr.radix);
|
||||
ppr.exponent = exponent;
|
||||
ppr.offset = [];
|
||||
ppr.factor = [];
|
||||
ppr.minOffset = mo;
|
||||
ppr.fullMask = 0;
|
||||
ppr.fullOffset = [];
|
||||
ppr.fullFactor = [];
|
||||
ppr.modulus = p.modulus = new sjcl.bn(Math.pow(2,exponent));
|
||||
|
||||
ppr.fullMask = 0|-Math.pow(2, exponent % ppr.radix);
|
||||
|
||||
for (i=0; i<coeff.length; i++) {
|
||||
ppr.offset[i] = Math.floor(coeff[i][0] / ppr.radix - tmp);
|
||||
ppr.fullOffset[i] = Math.ceil(coeff[i][0] / ppr.radix - tmp);
|
||||
ppr.factor[i] = coeff[i][1] * Math.pow(1/2, exponent - coeff[i][0] + ppr.offset[i] * ppr.radix);
|
||||
ppr.fullFactor[i] = coeff[i][1] * Math.pow(1/2, exponent - coeff[i][0] + ppr.fullOffset[i] * ppr.radix);
|
||||
ppr.modulus.addM(new sjcl.bn(Math.pow(2,coeff[i][0])*coeff[i][1]));
|
||||
ppr.minOffset = Math.min(ppr.minOffset, -ppr.offset[i]); // conservative
|
||||
}
|
||||
ppr._class = p;
|
||||
ppr.modulus.cnormalize();
|
||||
|
||||
/** Approximate reduction mod p. May leave a number which is negative or slightly larger than p. */
|
||||
ppr.reduce = function() {
|
||||
var i, k, l, mo = this.modOffset, limbs = this.limbs, aff, off = this.offset, ol = this.offset.length, fac = this.factor, ll;
|
||||
|
||||
i = this.minOffset;
|
||||
while (limbs.length > mo) {
|
||||
l = limbs.pop();
|
||||
ll = limbs.length;
|
||||
for (k=0; k<ol; k++) {
|
||||
limbs[ll+off[k]] -= fac[k] * l;
|
||||
}
|
||||
|
||||
i--;
|
||||
if (!i) {
|
||||
limbs.push(0);
|
||||
this.cnormalize();
|
||||
i = this.minOffset;
|
||||
}
|
||||
}
|
||||
this.cnormalize();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
ppr._strongReduce = (ppr.fullMask === -1) ? ppr.reduce : function() {
|
||||
var limbs = this.limbs, i = limbs.length - 1, k, l;
|
||||
this.reduce();
|
||||
if (i === this.modOffset - 1) {
|
||||
l = limbs[i] & this.fullMask;
|
||||
limbs[i] -= l;
|
||||
for (k=0; k<this.fullOffset.length; k++) {
|
||||
limbs[i+this.fullOffset[k]] -= this.fullFactor[k] * l;
|
||||
}
|
||||
this.normalize();
|
||||
}
|
||||
};
|
||||
|
||||
/** mostly constant-time, very expensive full reduction. */
|
||||
ppr.fullReduce = function() {
|
||||
var greater, i;
|
||||
// massively above the modulus, may be negative
|
||||
|
||||
this._strongReduce();
|
||||
// less than twice the modulus, may be negative
|
||||
|
||||
this.addM(this.modulus);
|
||||
this.addM(this.modulus);
|
||||
this.normalize();
|
||||
// probably 2-3x the modulus
|
||||
|
||||
this._strongReduce();
|
||||
// less than the power of 2. still may be more than
|
||||
// the modulus
|
||||
|
||||
// HACK: pad out to this length
|
||||
for (i=this.limbs.length; i<this.modOffset; i++) {
|
||||
this.limbs[i] = 0;
|
||||
}
|
||||
|
||||
// constant-time subtract modulus
|
||||
greater = this.greaterEquals(this.modulus);
|
||||
for (i=0; i<this.limbs.length; i++) {
|
||||
this.limbs[i] -= this.modulus.limbs[i] * greater;
|
||||
}
|
||||
this.cnormalize();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
ppr.inverse = function() {
|
||||
return (this.power(this.modulus.sub(2)));
|
||||
};
|
||||
|
||||
p.fromBits = sjcl.bn.fromBits;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
// a small Mersenne prime
|
||||
sjcl.bn.prime = {
|
||||
p127: sjcl.bn.pseudoMersennePrime(127, [[0,-1]]),
|
||||
|
||||
// Bernstein's prime for Curve25519
|
||||
p25519: sjcl.bn.pseudoMersennePrime(255, [[0,-19]]),
|
||||
|
||||
// NIST primes
|
||||
p192: sjcl.bn.pseudoMersennePrime(192, [[0,-1],[64,-1]]),
|
||||
p224: sjcl.bn.pseudoMersennePrime(224, [[0,1],[96,-1]]),
|
||||
p256: sjcl.bn.pseudoMersennePrime(256, [[0,-1],[96,1],[192,1],[224,-1]]),
|
||||
p384: sjcl.bn.pseudoMersennePrime(384, [[0,-1],[32,1],[96,-1],[128,-1]]),
|
||||
p521: sjcl.bn.pseudoMersennePrime(521, [[0,-1]])
|
||||
};
|
||||
|
||||
sjcl.bn.random = function(modulus, paranoia) {
|
||||
if (typeof modulus !== "object") { modulus = new sjcl.bn(modulus); }
|
||||
var words, i, l = modulus.limbs.length, m = modulus.limbs[l-1]+1, out = new sjcl.bn();
|
||||
while (true) {
|
||||
// get a sequence whose first digits make sense
|
||||
do {
|
||||
words = sjcl.random.randomWords(l, paranoia);
|
||||
if (words[l-1] < 0) { words[l-1] += 0x100000000; }
|
||||
} while (Math.floor(words[l-1] / m) === Math.floor(0x100000000 / m));
|
||||
words[l-1] %= m;
|
||||
|
||||
// mask off all the limbs
|
||||
for (i=0; i<l-1; i++) {
|
||||
words[i] &= modulus.radixMask;
|
||||
}
|
||||
|
||||
// check the rest of the digitssj
|
||||
out.limbs = words;
|
||||
if (!out.greaterEquals(modulus)) {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
115
core/cbc.js
115
core/cbc.js
|
@ -1,115 +0,0 @@
|
|||
/** @fileOverview CBC mode implementation
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace
|
||||
* Dangerous: CBC mode with PKCS#5 padding.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
if (sjcl.beware === undefined) {
|
||||
sjcl.beware = {};
|
||||
}
|
||||
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."
|
||||
] = function() {
|
||||
sjcl.mode.cbc = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
*/
|
||||
name: "cbc",
|
||||
|
||||
/** Encrypt in CBC mode with PKCS#5 padding.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} plaintext The plaintext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data. Must be empty.
|
||||
* @return The encrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
|
||||
*/
|
||||
encrypt: function(prp, plaintext, iv, adata) {
|
||||
if (adata && adata.length) {
|
||||
throw new sjcl.exception.invalid("cbc can't authenticate data");
|
||||
}
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("cbc iv must be 128 bits");
|
||||
}
|
||||
var i,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
bl = w.bitLength(plaintext),
|
||||
bp = 0,
|
||||
output = [];
|
||||
|
||||
if (bl&7) {
|
||||
throw new sjcl.exception.invalid("pkcs#5 padding only works for multiples of a byte");
|
||||
}
|
||||
|
||||
for (i=0; bp+128 <= bl; i+=4, bp+=128) {
|
||||
/* Encrypt a non-final block */
|
||||
iv = prp.encrypt(xor(iv, plaintext.slice(i,i+4)));
|
||||
output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
|
||||
}
|
||||
|
||||
/* Construct the pad. */
|
||||
bl = (16 - ((bl >> 3) & 15)) * 0x1010101;
|
||||
|
||||
/* Pad and encrypt. */
|
||||
iv = prp.encrypt(xor(iv,w.concat(plaintext,[bl,bl,bl,bl]).slice(i,i+4)));
|
||||
output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
|
||||
return output;
|
||||
},
|
||||
|
||||
/** Decrypt in CBC mode.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} ciphertext The ciphertext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data. It must be empty.
|
||||
* @return The decrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
|
||||
* @throws {sjcl.exception.corrupt} if if the message is corrupt.
|
||||
*/
|
||||
decrypt: function(prp, ciphertext, iv, adata) {
|
||||
if (adata && adata.length) {
|
||||
throw new sjcl.exception.invalid("cbc can't authenticate data");
|
||||
}
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("cbc iv must be 128 bits");
|
||||
}
|
||||
if ((sjcl.bitArray.bitLength(ciphertext) & 127) || !ciphertext.length) {
|
||||
throw new sjcl.exception.corrupt("cbc ciphertext must be a positive multiple of the block size");
|
||||
}
|
||||
var i,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
bi, bo,
|
||||
output = [];
|
||||
|
||||
adata = adata || [];
|
||||
|
||||
for (i=0; i<ciphertext.length; i+=4) {
|
||||
bi = ciphertext.slice(i,i+4);
|
||||
bo = xor(iv,prp.decrypt(bi));
|
||||
output.splice(i,0,bo[0],bo[1],bo[2],bo[3]);
|
||||
iv = bi;
|
||||
}
|
||||
|
||||
/* check and remove the pad */
|
||||
bi = output[i-1] & 255;
|
||||
if (bi == 0 || bi > 16) {
|
||||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
|
||||
}
|
||||
bo = bi * 0x1010101;
|
||||
if (!w.equal(w.bitSlice([bo,bo,bo,bo], 0, bi*8),
|
||||
w.bitSlice(output, output.length*32 - bi*8, output.length*32))) {
|
||||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
|
||||
}
|
||||
|
||||
return w.bitSlice(output, 0, output.length*32 - bi*8);
|
||||
}
|
||||
};
|
||||
};
|
185
core/ccm.js
185
core/ccm.js
|
@ -1,185 +0,0 @@
|
|||
/** @fileOverview CCM mode implementation.
|
||||
*
|
||||
* Special thanks to Roy Nicholson for pointing out a bug in our
|
||||
* implementation.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace CTR mode with CBC MAC. */
|
||||
sjcl.mode.ccm = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
*/
|
||||
name: "ccm",
|
||||
|
||||
/** Encrypt in CCM mode.
|
||||
* @static
|
||||
* @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} plaintext The plaintext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data.
|
||||
* @param {Number} [tlen=64] the desired tag length, in bits.
|
||||
* @return {bitArray} The encrypted data, an array of bytes.
|
||||
*/
|
||||
encrypt: function(prf, plaintext, iv, adata, tlen) {
|
||||
var L, i, out = plaintext.slice(0), tag, w=sjcl.bitArray, ivl = w.bitLength(iv) / 8, ol = w.bitLength(out) / 8;
|
||||
tlen = tlen || 64;
|
||||
adata = adata || [];
|
||||
|
||||
if (ivl < 7) {
|
||||
throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");
|
||||
}
|
||||
|
||||
// compute the length of the length
|
||||
for (L=2; L<4 && ol >>> 8*L; L++) {}
|
||||
if (L < 15 - ivl) { L = 15-ivl; }
|
||||
iv = w.clamp(iv,8*(15-L));
|
||||
|
||||
// compute the tag
|
||||
tag = sjcl.mode.ccm._computeTag(prf, plaintext, iv, adata, tlen, L);
|
||||
|
||||
// encrypt
|
||||
out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L);
|
||||
|
||||
return w.concat(out.data, out.tag);
|
||||
},
|
||||
|
||||
/** Decrypt in CCM mode.
|
||||
* @static
|
||||
* @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} ciphertext The ciphertext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [[]] adata The authenticated data.
|
||||
* @param {Number} [64] tlen the desired tag length, in bits.
|
||||
* @return {bitArray} The decrypted data.
|
||||
*/
|
||||
decrypt: function(prf, ciphertext, iv, adata, tlen) {
|
||||
tlen = tlen || 64;
|
||||
adata = adata || [];
|
||||
var L, i,
|
||||
w=sjcl.bitArray,
|
||||
ivl = w.bitLength(iv) / 8,
|
||||
ol = w.bitLength(ciphertext),
|
||||
out = w.clamp(ciphertext, ol - tlen),
|
||||
tag = w.bitSlice(ciphertext, ol - tlen), tag2;
|
||||
|
||||
|
||||
ol = (ol - tlen) / 8;
|
||||
|
||||
if (ivl < 7) {
|
||||
throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");
|
||||
}
|
||||
|
||||
// compute the length of the length
|
||||
for (L=2; L<4 && ol >>> 8*L; L++) {}
|
||||
if (L < 15 - ivl) { L = 15-ivl; }
|
||||
iv = w.clamp(iv,8*(15-L));
|
||||
|
||||
// decrypt
|
||||
out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L);
|
||||
|
||||
// check the tag
|
||||
tag2 = sjcl.mode.ccm._computeTag(prf, out.data, iv, adata, tlen, L);
|
||||
if (!w.equal(out.tag, tag2)) {
|
||||
throw new sjcl.exception.corrupt("ccm: tag doesn't match");
|
||||
}
|
||||
|
||||
return out.data;
|
||||
},
|
||||
|
||||
/* Compute the (unencrypted) authentication tag, according to the CCM specification
|
||||
* @param {Object} prf The pseudorandom function.
|
||||
* @param {bitArray} plaintext The plaintext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} adata The authenticated data.
|
||||
* @param {Number} tlen the desired tag length, in bits.
|
||||
* @return {bitArray} The tag, but not yet encrypted.
|
||||
* @private
|
||||
*/
|
||||
_computeTag: function(prf, plaintext, iv, adata, tlen, L) {
|
||||
// compute B[0]
|
||||
var q, mac, field = 0, offset = 24, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4;
|
||||
|
||||
tlen /= 8;
|
||||
|
||||
// check tag length and message length
|
||||
if (tlen % 2 || tlen < 4 || tlen > 16) {
|
||||
throw new sjcl.exception.invalid("ccm: invalid tag length");
|
||||
}
|
||||
|
||||
if (adata.length > 0xFFFFFFFF || plaintext.length > 0xFFFFFFFF) {
|
||||
// I don't want to deal with extracting high words from doubles.
|
||||
throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");
|
||||
}
|
||||
|
||||
// mac the flags
|
||||
mac = [w.partial(8, (adata.length ? 1<<6 : 0) | (tlen-2) << 2 | L-1)];
|
||||
|
||||
// mac the iv and length
|
||||
mac = w.concat(mac, iv);
|
||||
mac[3] |= w.bitLength(plaintext)/8;
|
||||
mac = prf.encrypt(mac);
|
||||
|
||||
|
||||
if (adata.length) {
|
||||
// mac the associated data. start with its length...
|
||||
tmp = w.bitLength(adata)/8;
|
||||
if (tmp <= 0xFEFF) {
|
||||
macData = [w.partial(16, tmp)];
|
||||
} else if (tmp <= 0xFFFFFFFF) {
|
||||
macData = w.concat([w.partial(16,0xFFFE)], [tmp]);
|
||||
} // else ...
|
||||
|
||||
// mac the data itself
|
||||
macData = w.concat(macData, adata);
|
||||
for (i=0; i<macData.length; i += 4) {
|
||||
mac = prf.encrypt(xor(mac, macData.slice(i,i+4).concat([0,0,0])));
|
||||
}
|
||||
}
|
||||
|
||||
// mac the plaintext
|
||||
for (i=0; i<plaintext.length; i+=4) {
|
||||
mac = prf.encrypt(xor(mac, plaintext.slice(i,i+4).concat([0,0,0])));
|
||||
}
|
||||
|
||||
return w.clamp(mac, tlen * 8);
|
||||
},
|
||||
|
||||
/** CCM CTR mode.
|
||||
* Encrypt or decrypt data and tag with the prf in CCM-style CTR mode.
|
||||
* May mutate its arguments.
|
||||
* @param {Object} prf The PRF.
|
||||
* @param {bitArray} data The data to be encrypted or decrypted.
|
||||
* @param {bitArray} iv The initialization vector.
|
||||
* @param {bitArray} tag The authentication tag.
|
||||
* @param {Number} tlen The length of th etag, in bits.
|
||||
* @param {Number} L The CCM L value.
|
||||
* @return {Object} An object with data and tag, the en/decryption of data and tag values.
|
||||
* @private
|
||||
*/
|
||||
_ctrMode: function(prf, data, iv, tag, tlen, L) {
|
||||
var enc, i, w=sjcl.bitArray, xor = w._xor4, ctr, b, l = data.length, bl=w.bitLength(data);
|
||||
|
||||
// start the ctr
|
||||
ctr = w.concat([w.partial(8,L-1)],iv).concat([0,0,0]).slice(0,4);
|
||||
|
||||
// en/decrypt the tag
|
||||
tag = w.bitSlice(xor(tag,prf.encrypt(ctr)), 0, tlen);
|
||||
|
||||
// en/decrypt the data
|
||||
if (!l) { return {tag:tag, data:[]}; }
|
||||
|
||||
for (i=0; i<l; i+=4) {
|
||||
ctr[3]++;
|
||||
enc = prf.encrypt(ctr);
|
||||
data[i] ^= enc[0];
|
||||
data[i+1] ^= enc[1];
|
||||
data[i+2] ^= enc[2];
|
||||
data[i+3] ^= enc[3];
|
||||
}
|
||||
return { tag:tag, data:w.clamp(data,bl) };
|
||||
}
|
||||
};
|
|
@ -1,63 +0,0 @@
|
|||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Base64 encoding/decoding */
|
||||
sjcl.codec.base64 = {
|
||||
/** The base64 alphabet.
|
||||
* @private
|
||||
*/
|
||||
_chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
||||
|
||||
/** Convert from a bitArray to a base64 string. */
|
||||
fromBits: function (arr, _noEquals, _url) {
|
||||
var out = "", i, bits=0, c = sjcl.codec.base64._chars, ta=0, bl = sjcl.bitArray.bitLength(arr);
|
||||
if (_url) c = c.substr(0,62) + '-_';
|
||||
for (i=0; out.length * 6 < bl; ) {
|
||||
out += c.charAt((ta ^ arr[i]>>>bits) >>> 26);
|
||||
if (bits < 6) {
|
||||
ta = arr[i] << (6-bits);
|
||||
bits += 26;
|
||||
i++;
|
||||
} else {
|
||||
ta <<= 6;
|
||||
bits -= 6;
|
||||
}
|
||||
}
|
||||
while ((out.length & 3) && !_noEquals) { out += "="; }
|
||||
return out;
|
||||
},
|
||||
|
||||
/** Convert from a base64 string to a bitArray */
|
||||
toBits: function(str, _url) {
|
||||
str = str.replace(/\s|=/g,'');
|
||||
var out = [], i, bits=0, c = sjcl.codec.base64._chars, ta=0, x;
|
||||
if (_url) c = c.substr(0,62) + '-_';
|
||||
for (i=0; i<str.length; i++) {
|
||||
x = c.indexOf(str.charAt(i));
|
||||
if (x < 0) {
|
||||
throw new sjcl.exception.invalid("this isn't base64!");
|
||||
}
|
||||
if (bits > 26) {
|
||||
bits -= 26;
|
||||
out.push(ta ^ x>>>bits);
|
||||
ta = x << (32-bits);
|
||||
} else {
|
||||
bits += 6;
|
||||
ta ^= x << (32-bits);
|
||||
}
|
||||
}
|
||||
if (bits&56) {
|
||||
out.push(sjcl.bitArray.partial(bits&56, ta, 1));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.codec.base64url = {
|
||||
fromBits: function (arr) { return sjcl.codec.base64.fromBits(arr,1,1); },
|
||||
toBits: function (str) { return sjcl.codec.base64.toBits(str,1); }
|
||||
};
|
|
@ -1,37 +0,0 @@
|
|||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Arrays of bytes */
|
||||
sjcl.codec.bytes = {
|
||||
/** Convert from a bitArray to an array of bytes. */
|
||||
fromBits: function (arr) {
|
||||
var out = [], bl = sjcl.bitArray.bitLength(arr), i, tmp;
|
||||
for (i=0; i<bl/8; i++) {
|
||||
if ((i&3) === 0) {
|
||||
tmp = arr[i/4];
|
||||
}
|
||||
out.push(tmp >>> 24);
|
||||
tmp <<= 8;
|
||||
}
|
||||
return out;
|
||||
},
|
||||
/** Convert from an array of bytes to a bitArray. */
|
||||
toBits: function (bytes) {
|
||||
var out = [], i, tmp=0;
|
||||
for (i=0; i<bytes.length; i++) {
|
||||
tmp = tmp << 8 | bytes[i];
|
||||
if ((i&3) === 3) {
|
||||
out.push(tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
if (i&3) {
|
||||
out.push(sjcl.bitArray.partial(8*(i&3), tmp));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
|
@ -1,30 +0,0 @@
|
|||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Hexadecimal */
|
||||
sjcl.codec.hex = {
|
||||
/** Convert from a bitArray to a hex string. */
|
||||
fromBits: function (arr) {
|
||||
var out = "", i, x;
|
||||
for (i=0; i<arr.length; i++) {
|
||||
out += ((arr[i]|0)+0xF00000000000).toString(16).substr(4);
|
||||
}
|
||||
return out.substr(0, sjcl.bitArray.bitLength(arr)/4);//.replace(/(.{8})/g, "$1 ");
|
||||
},
|
||||
/** Convert from a hex string to a bitArray. */
|
||||
toBits: function (str) {
|
||||
var i, out=[], len;
|
||||
str = str.replace(/\s|0x/g, "");
|
||||
len = str.length;
|
||||
str = str + "00000000";
|
||||
for (i=0; i<str.length; i+=8) {
|
||||
out.push(parseInt(str.substr(i,8),16)^0);
|
||||
}
|
||||
return sjcl.bitArray.clamp(out, len*4);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace UTF-8 strings */
|
||||
sjcl.codec.utf8String = {
|
||||
/** Convert from a bitArray to a UTF-8 string. */
|
||||
fromBits: function (arr) {
|
||||
var out = "", bl = sjcl.bitArray.bitLength(arr), i, tmp;
|
||||
for (i=0; i<bl/8; i++) {
|
||||
if ((i&3) === 0) {
|
||||
tmp = arr[i/4];
|
||||
}
|
||||
out += String.fromCharCode(tmp >>> 24);
|
||||
tmp <<= 8;
|
||||
}
|
||||
return decodeURIComponent(escape(out));
|
||||
},
|
||||
|
||||
/** Convert from a UTF-8 string to a bitArray. */
|
||||
toBits: function (str) {
|
||||
str = unescape(encodeURIComponent(str));
|
||||
var out = [], i, tmp=0;
|
||||
for (i=0; i<str.length; i++) {
|
||||
tmp = tmp << 8 | str.charCodeAt(i);
|
||||
if ((i&3) === 3) {
|
||||
out.push(tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
if (i&3) {
|
||||
out.push(sjcl.bitArray.partial(8*(i&3), tmp));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
|
@ -1,279 +0,0 @@
|
|||
/** @fileOverview Convenince functions centered around JSON encapsulation.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace JSON encapsulation */
|
||||
sjcl.json = {
|
||||
/** Default values for encryption */
|
||||
defaults: { v:1, iter:1000, ks:128, ts:64, mode:"ccm", adata:"", cipher:"aes" },
|
||||
|
||||
/** Simple encryption function.
|
||||
* @param {String|bitArray} password The password or key.
|
||||
* @param {String} plaintext The data to encrypt.
|
||||
* @param {Object} [params] The parameters including tag, iv and salt.
|
||||
* @param {Object} [rp] A returned version with filled-in parameters.
|
||||
* @return {String} The ciphertext.
|
||||
* @throws {sjcl.exception.invalid} if a parameter is invalid.
|
||||
*/
|
||||
encrypt: function (password, plaintext, params, rp) {
|
||||
params = params || {};
|
||||
rp = rp || {};
|
||||
|
||||
var j = sjcl.json, p = j._add({ iv: sjcl.random.randomWords(4,0) },
|
||||
j.defaults), tmp, prp, adata;
|
||||
j._add(p, params);
|
||||
adata = p.adata;
|
||||
if (typeof p.salt === "string") {
|
||||
p.salt = sjcl.codec.base64.toBits(p.salt);
|
||||
}
|
||||
if (typeof p.iv === "string") {
|
||||
p.iv = sjcl.codec.base64.toBits(p.iv);
|
||||
}
|
||||
|
||||
if (!sjcl.mode[p.mode] ||
|
||||
!sjcl.cipher[p.cipher] ||
|
||||
(typeof password === "string" && p.iter <= 100) ||
|
||||
(p.ts !== 64 && p.ts !== 96 && p.ts !== 128) ||
|
||||
(p.ks !== 128 && p.ks !== 192 && p.ks !== 256) ||
|
||||
(p.iv.length < 2 || p.iv.length > 4)) {
|
||||
throw new sjcl.exception.invalid("json encrypt: invalid parameters");
|
||||
}
|
||||
|
||||
if (typeof password === "string") {
|
||||
tmp = sjcl.misc.cachedPbkdf2(password, p);
|
||||
password = tmp.key.slice(0,p.ks/32);
|
||||
p.salt = tmp.salt;
|
||||
}
|
||||
if (typeof plaintext === "string") {
|
||||
plaintext = sjcl.codec.utf8String.toBits(plaintext);
|
||||
}
|
||||
if (typeof adata === "string") {
|
||||
adata = sjcl.codec.utf8String.toBits(adata);
|
||||
}
|
||||
prp = new sjcl.cipher[p.cipher](password);
|
||||
|
||||
/* return the json data */
|
||||
j._add(rp, p);
|
||||
rp.key = password;
|
||||
|
||||
/* do the encryption */
|
||||
p.ct = sjcl.mode[p.mode].encrypt(prp, plaintext, p.iv, adata, p.ts);
|
||||
|
||||
//return j.encode(j._subtract(p, j.defaults));
|
||||
return j.encode(p);
|
||||
},
|
||||
|
||||
/** Simple decryption function.
|
||||
* @param {String|bitArray} password The password or key.
|
||||
* @param {String} ciphertext The ciphertext to decrypt.
|
||||
* @param {Object} [params] Additional non-default parameters.
|
||||
* @param {Object} [rp] A returned object with filled parameters.
|
||||
* @return {String} The plaintext.
|
||||
* @throws {sjcl.exception.invalid} if a parameter is invalid.
|
||||
* @throws {sjcl.exception.corrupt} if the ciphertext is corrupt.
|
||||
*/
|
||||
decrypt: function (password, ciphertext, params, rp) {
|
||||
params = params || {};
|
||||
rp = rp || {};
|
||||
|
||||
var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),j.decode(ciphertext)), params, true), ct, tmp, prp, adata=p.adata;
|
||||
if (typeof p.salt === "string") {
|
||||
p.salt = sjcl.codec.base64.toBits(p.salt);
|
||||
}
|
||||
if (typeof p.iv === "string") {
|
||||
p.iv = sjcl.codec.base64.toBits(p.iv);
|
||||
}
|
||||
|
||||
if (!sjcl.mode[p.mode] ||
|
||||
!sjcl.cipher[p.cipher] ||
|
||||
(typeof password === "string" && p.iter <= 100) ||
|
||||
(p.ts !== 64 && p.ts !== 96 && p.ts !== 128) ||
|
||||
(p.ks !== 128 && p.ks !== 192 && p.ks !== 256) ||
|
||||
(!p.iv) ||
|
||||
(p.iv.length < 2 || p.iv.length > 4)) {
|
||||
throw new sjcl.exception.invalid("json decrypt: invalid parameters");
|
||||
}
|
||||
|
||||
if (typeof password === "string") {
|
||||
tmp = sjcl.misc.cachedPbkdf2(password, p);
|
||||
password = tmp.key.slice(0,p.ks/32);
|
||||
p.salt = tmp.salt;
|
||||
}
|
||||
if (typeof adata === "string") {
|
||||
adata = sjcl.codec.utf8String.toBits(adata);
|
||||
}
|
||||
prp = new sjcl.cipher[p.cipher](password);
|
||||
|
||||
/* do the decryption */
|
||||
ct = sjcl.mode[p.mode].decrypt(prp, p.ct, p.iv, adata, p.ts);
|
||||
|
||||
/* return the json data */
|
||||
j._add(rp, p);
|
||||
rp.key = password;
|
||||
|
||||
return sjcl.codec.utf8String.fromBits(ct);
|
||||
},
|
||||
|
||||
/** Encode a flat structure into a JSON string.
|
||||
* @param {Object} obj The structure to encode.
|
||||
* @return {String} A JSON string.
|
||||
* @throws {sjcl.exception.invalid} if obj has a non-alphanumeric property.
|
||||
* @throws {sjcl.exception.bug} if a parameter has an unsupported type.
|
||||
*/
|
||||
encode: function (obj) {
|
||||
var i, out='{', comma='';
|
||||
for (i in obj) {
|
||||
if (obj.hasOwnProperty(i)) {
|
||||
if (!i.match(/^[a-z0-9]+$/i)) {
|
||||
throw new sjcl.exception.invalid("json encode: invalid property name");
|
||||
}
|
||||
out += comma + '"' + i + '"' + ':';
|
||||
comma = ',';
|
||||
|
||||
switch (typeof obj[i]) {
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
out += obj[i];
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
out += '"' + escape(obj[i]) + '"';
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
out += '"' + sjcl.codec.base64.fromBits(obj[i],1) + '"';
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new sjcl.exception.bug("json encode: unsupported type");
|
||||
}
|
||||
}
|
||||
}
|
||||
return out+'}';
|
||||
},
|
||||
|
||||
/** Decode a simple (flat) JSON string into a structure. The ciphertext,
|
||||
* adata, salt and iv will be base64-decoded.
|
||||
* @param {String} str The string.
|
||||
* @return {Object} The decoded structure.
|
||||
* @throws {sjcl.exception.invalid} if str isn't (simple) JSON.
|
||||
*/
|
||||
decode: function (str) {
|
||||
str = str.replace(/\s/g,'');
|
||||
if (!str.match(/^\{.*\}$/)) {
|
||||
throw new sjcl.exception.invalid("json decode: this isn't json!");
|
||||
}
|
||||
var a = str.replace(/^\{|\}$/g, '').split(/,/), out={}, i, m;
|
||||
for (i=0; i<a.length; i++) {
|
||||
if (!(m=a[i].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i))) {
|
||||
throw new sjcl.exception.invalid("json decode: this isn't json!");
|
||||
}
|
||||
if (m[3]) {
|
||||
out[m[2]] = parseInt(m[3],10);
|
||||
} else {
|
||||
out[m[2]] = m[2].match(/^(ct|salt|iv)$/) ? sjcl.codec.base64.toBits(m[4]) : unescape(m[4]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
/** Insert all elements of src into target, modifying and returning target.
|
||||
* @param {Object} target The object to be modified.
|
||||
* @param {Object} src The object to pull data from.
|
||||
* @param {boolean} [requireSame=false] If true, throw an exception if any field of target differs from corresponding field of src.
|
||||
* @return {Object} target.
|
||||
* @private
|
||||
*/
|
||||
_add: function (target, src, requireSame) {
|
||||
if (target === undefined) { target = {}; }
|
||||
if (src === undefined) { return target; }
|
||||
var i;
|
||||
for (i in src) {
|
||||
if (src.hasOwnProperty(i)) {
|
||||
if (requireSame && target[i] !== undefined && target[i] !== src[i]) {
|
||||
throw new sjcl.exception.invalid("required parameter overridden");
|
||||
}
|
||||
target[i] = src[i];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
},
|
||||
|
||||
/** Remove all elements of minus from plus. Does not modify plus.
|
||||
* @private
|
||||
*/
|
||||
_subtract: function (plus, minus) {
|
||||
var out = {}, i;
|
||||
|
||||
for (i in plus) {
|
||||
if (plus.hasOwnProperty(i) && plus[i] !== minus[i]) {
|
||||
out[i] = plus[i];
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
/** Return only the specified elements of src.
|
||||
* @private
|
||||
*/
|
||||
_filter: function (src, filter) {
|
||||
var out = {}, i;
|
||||
for (i=0; i<filter.length; i++) {
|
||||
if (src[filter[i]] !== undefined) {
|
||||
out[filter[i]] = src[filter[i]];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/** Simple encryption function; convenient shorthand for sjcl.json.encrypt.
|
||||
* @param {String|bitArray} password The password or key.
|
||||
* @param {String} plaintext The data to encrypt.
|
||||
* @param {Object} [params] The parameters including tag, iv and salt.
|
||||
* @param {Object} [rp] A returned version with filled-in parameters.
|
||||
* @return {String} The ciphertext.
|
||||
*/
|
||||
sjcl.encrypt = sjcl.json.encrypt;
|
||||
|
||||
/** Simple decryption function; convenient shorthand for sjcl.json.decrypt.
|
||||
* @param {String|bitArray} password The password or key.
|
||||
* @param {String} ciphertext The ciphertext to decrypt.
|
||||
* @param {Object} [params] Additional non-default parameters.
|
||||
* @param {Object} [rp] A returned object with filled parameters.
|
||||
* @return {String} The plaintext.
|
||||
*/
|
||||
sjcl.decrypt = sjcl.json.decrypt;
|
||||
|
||||
/** The cache for cachedPbkdf2.
|
||||
* @private
|
||||
*/
|
||||
sjcl.misc._pbkdf2Cache = {};
|
||||
|
||||
/** Cached PBKDF2 key derivation.
|
||||
* @param {String} password The password.
|
||||
* @param {Object} [params] The derivation params (iteration count and optional salt).
|
||||
* @return {Object} The derived data in key, the salt in salt.
|
||||
*/
|
||||
sjcl.misc.cachedPbkdf2 = function (password, obj) {
|
||||
var cache = sjcl.misc._pbkdf2Cache, c, cp, str, salt, iter;
|
||||
|
||||
obj = obj || {};
|
||||
iter = obj.iter || 1000;
|
||||
|
||||
/* open the cache for this password and iteration count */
|
||||
cp = cache[password] = cache[password] || {};
|
||||
c = cp[iter] = cp[iter] || { firstSalt: (obj.salt && obj.salt.length) ?
|
||||
obj.salt.slice(0) : sjcl.random.randomWords(2,0) };
|
||||
|
||||
salt = (obj.salt === undefined) ? c.firstSalt : obj.salt;
|
||||
|
||||
c[salt] = c[salt] || sjcl.misc.pbkdf2(password, salt, obj.iter);
|
||||
return { key: c[salt].slice(0), salt:salt.slice(0) };
|
||||
};
|
||||
|
||||
|
380
core/ecc.js
380
core/ecc.js
|
@ -1,380 +0,0 @@
|
|||
sjcl.ecc = {};
|
||||
|
||||
/**
|
||||
* Represents a point on a curve in affine coordinates.
|
||||
* @constructor
|
||||
* @param {sjcl.ecc.curve} curve The curve that this point lies on.
|
||||
* @param {bigInt} x The x coordinate.
|
||||
* @param {bigInt} y The y coordinate.
|
||||
*/
|
||||
sjcl.ecc.point = function(curve,x,y) {
|
||||
if (x === undefined) {
|
||||
this.isIdentity = true;
|
||||
} else {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.isIdentity = false;
|
||||
}
|
||||
this.curve = curve;
|
||||
};
|
||||
|
||||
|
||||
|
||||
sjcl.ecc.point.prototype = {
|
||||
toJac: function() {
|
||||
return new sjcl.ecc.pointJac(this.curve, this.x, this.y, new this.curve.field(1));
|
||||
},
|
||||
|
||||
mult: function(k) {
|
||||
return this.toJac().mult(k, this).toAffine();
|
||||
},
|
||||
|
||||
/**
|
||||
* Multiply this point by k, added to affine2*k2, and return the answer in Jacobian coordinates.
|
||||
* @param {bigInt} k The coefficient to multiply this by.
|
||||
* @param {bigInt} k2 The coefficient to multiply affine2 this by.
|
||||
* @param {sjcl.ecc.point} affine The other point in affine coordinates.
|
||||
* @return {sjcl.ecc.pointJac} The result of the multiplication and addition, in Jacobian coordinates.
|
||||
*/
|
||||
mult2: function(k, k2, affine2) {
|
||||
return this.toJac().mult2(k, this, k2, affine2).toAffine();
|
||||
},
|
||||
|
||||
multiples: function() {
|
||||
var m, i, j;
|
||||
if (this._multiples === undefined) {
|
||||
j = this.toJac().doubl();
|
||||
m = this._multiples = [new sjcl.ecc.point(this.curve), this, j.toAffine()];
|
||||
for (i=3; i<16; i++) {
|
||||
j = j.add(this);
|
||||
m.push(j.toAffine());
|
||||
}
|
||||
}
|
||||
return this._multiples;
|
||||
},
|
||||
|
||||
isValid: function() {
|
||||
return this.y.square().equals(this.curve.b.add(this.x.mul(this.curve.a.add(this.x.square()))));
|
||||
},
|
||||
|
||||
toBits: function() {
|
||||
return sjcl.bitArray.concat(this.x.toBits(), this.y.toBits());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a point on a curve in Jacobian coordinates. Coordinates can be specified as bigInts or strings (which
|
||||
* will be converted to bigInts).
|
||||
*
|
||||
* @constructor
|
||||
* @param {bigInt/string} x The x coordinate.
|
||||
* @param {bigInt/string} y The y coordinate.
|
||||
* @param {bigInt/string} z The z coordinate.
|
||||
* @param {sjcl.ecc.curve} curve The curve that this point lies on.
|
||||
*/
|
||||
sjcl.ecc.pointJac = function(curve, x, y, z) {
|
||||
if (x === undefined) {
|
||||
this.isIdentity = true;
|
||||
} else {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.isIdentity = false;
|
||||
}
|
||||
this.curve = curve;
|
||||
};
|
||||
|
||||
sjcl.ecc.pointJac.prototype = {
|
||||
/**
|
||||
* Adds S and T and returns the result in Jacobian coordinates. Note that S must be in Jacobian coordinates and T must be in affine coordinates.
|
||||
* @param {sjcl.ecc.pointJac} S One of the points to add, in Jacobian coordinates.
|
||||
* @param {sjcl.ecc.point} T The other point to add, in affine coordinates.
|
||||
* @return {sjcl.ecc.pointJac} The sum of the two points, in Jacobian coordinates.
|
||||
*/
|
||||
add: function(T) {
|
||||
var S = this, sz2, c, d, c2, x1, x2, x, y1, y2, y, z;
|
||||
if (S.curve !== T.curve) {
|
||||
throw("sjcl.ecc.add(): Points must be on the same curve to add them!");
|
||||
}
|
||||
|
||||
if (S.isIdentity) {
|
||||
return T.toJac();
|
||||
} else if (T.isIdentity) {
|
||||
return S;
|
||||
}
|
||||
|
||||
sz2 = S.z.square();
|
||||
c = T.x.mul(sz2).subM(S.x);
|
||||
|
||||
if (c.equals(0)) {
|
||||
if (S.y.equals(T.y.mul(sz2.mul(S.z)))) {
|
||||
// same point
|
||||
return S.doubl();
|
||||
} else {
|
||||
// inverses
|
||||
return new sjcl.ecc.pointJac(S.curve);
|
||||
}
|
||||
}
|
||||
|
||||
d = T.y.mul(sz2.mul(S.z)).subM(S.y);
|
||||
c2 = c.square();
|
||||
|
||||
x1 = d.square();
|
||||
x2 = c.square().mul(c).addM( S.x.add(S.x).mul(c2) );
|
||||
x = x1.subM(x2);
|
||||
|
||||
y1 = S.x.mul(c2).subM(x).mul(d);
|
||||
y2 = S.y.mul(c.square().mul(c));
|
||||
y = y1.subM(y2);
|
||||
|
||||
z = S.z.mul(c);
|
||||
|
||||
return new sjcl.ecc.pointJac(this.curve,x,y,z);
|
||||
},
|
||||
|
||||
/**
|
||||
* doubles this point.
|
||||
* @return {sjcl.ecc.pointJac} The doubled point.
|
||||
*/
|
||||
doubl: function() {
|
||||
if (this.isIdentity) { return this; }
|
||||
|
||||
var
|
||||
y2 = this.y.square(),
|
||||
a = y2.mul(this.x.mul(4)),
|
||||
b = y2.square().mul(8),
|
||||
z2 = this.z.square(),
|
||||
c = this.x.sub(z2).mul(3).mul(this.x.add(z2)),
|
||||
x = c.square().subM(a).subM(a),
|
||||
y = a.sub(x).mul(c).subM(b),
|
||||
z = this.y.add(this.y).mul(this.z);
|
||||
return new sjcl.ecc.pointJac(this.curve, x, y, z);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a copy of this point converted to affine coordinates.
|
||||
* @return {sjcl.ecc.point} The converted point.
|
||||
*/
|
||||
toAffine: function() {
|
||||
if (this.isIdentity || this.z.equals(0)) {
|
||||
return new sjcl.ecc.point(this.curve);
|
||||
}
|
||||
var zi = this.z.inverse(), zi2 = zi.square();
|
||||
return new sjcl.ecc.point(this.curve, this.x.mul(zi2).fullReduce(), this.y.mul(zi2.mul(zi)).fullReduce());
|
||||
},
|
||||
|
||||
/**
|
||||
* Multiply this point by k and return the answer in Jacobian coordinates.
|
||||
* @param {bigInt} k The coefficient to multiply by.
|
||||
* @param {sjcl.ecc.point} affine This point in affine coordinates.
|
||||
* @return {sjcl.ecc.pointJac} The result of the multiplication, in Jacobian coordinates.
|
||||
*/
|
||||
mult: function(k, affine) {
|
||||
if (typeof(k) === "number") {
|
||||
k = [k];
|
||||
} else if (k.limbs !== undefined) {
|
||||
k = k.normalize().limbs;
|
||||
}
|
||||
|
||||
var i, j, out = new sjcl.ecc.point(this.curve).toJac(), multiples = affine.multiples();
|
||||
|
||||
for (i=k.length-1; i>=0; i--) {
|
||||
for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) {
|
||||
out = out.doubl().doubl().doubl().doubl().add(multiples[k[i]>>j & 0xF]);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
/**
|
||||
* Multiply this point by k, added to affine2*k2, and return the answer in Jacobian coordinates.
|
||||
* @param {bigInt} k The coefficient to multiply this by.
|
||||
* @param {sjcl.ecc.point} affine This point in affine coordinates.
|
||||
* @param {bigInt} k2 The coefficient to multiply affine2 this by.
|
||||
* @param {sjcl.ecc.point} affine The other point in affine coordinates.
|
||||
* @return {sjcl.ecc.pointJac} The result of the multiplication and addition, in Jacobian coordinates.
|
||||
*/
|
||||
mult2: function(k1, affine, k2, affine2) {
|
||||
if (typeof(k1) === "number") {
|
||||
k1 = [k1];
|
||||
} else if (k1.limbs !== undefined) {
|
||||
k1 = k1.normalize().limbs;
|
||||
}
|
||||
|
||||
if (typeof(k2) === "number") {
|
||||
k2 = [k2];
|
||||
} else if (k2.limbs !== undefined) {
|
||||
k2 = k2.normalize().limbs;
|
||||
}
|
||||
|
||||
var i, j, out = new sjcl.ecc.point(this.curve).toJac(), m1 = affine.multiples(),
|
||||
m2 = affine2.multiples(), l1, l2;
|
||||
|
||||
for (i=Math.max(k1.length,k2.length)-1; i>=0; i--) {
|
||||
l1 = k1[i] | 0;
|
||||
l2 = k2[i] | 0;
|
||||
for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) {
|
||||
out = out.doubl().doubl().doubl().doubl().add(m1[l1>>j & 0xF]).add(m2[l2>>j & 0xF]);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
isValid: function() {
|
||||
var z2 = this.z.square(), z4 = z2.square(), z6 = z4.mul(z2);
|
||||
return this.y.square().equals(
|
||||
this.curve.b.mul(z6).add(this.x.mul(
|
||||
this.curve.a.mul(z4).add(this.x.square()))));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct an elliptic curve. Most users will not use this and instead start with one of the NIST curves defined below.
|
||||
*
|
||||
* @constructor
|
||||
* @param {bigInt} p The prime modulus.
|
||||
* @param {bigInt} r The prime order of the curve.
|
||||
* @param {bigInt} a The constant a in the equation of the curve y^2 = x^3 + ax + b (for NIST curves, a is always -3).
|
||||
* @param {bigInt} x The x coordinate of a base point of the curve.
|
||||
* @param {bigInt} y The y coordinate of a base point of the curve.
|
||||
*/
|
||||
sjcl.ecc.curve = function(Field, r, a, b, x, y) {
|
||||
this.field = Field;
|
||||
this.r = Field.prototype.modulus.sub(r);
|
||||
this.a = new Field(a);
|
||||
this.b = new Field(b);
|
||||
this.G = new sjcl.ecc.point(this, new Field(x), new Field(y));
|
||||
};
|
||||
|
||||
sjcl.ecc.curve.prototype.fromBits = function (bits) {
|
||||
var w = sjcl.bitArray, l = this.field.prototype.exponent + 7 & -8,
|
||||
p = new sjcl.ecc.point(this, this.field.fromBits(w.bitSlice(bits, 0, l)),
|
||||
this.field.fromBits(w.bitSlice(bits, l, 2*l)));
|
||||
if (!p.isValid()) {
|
||||
throw new sjcl.exception.corrupt("not on the curve!");
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
sjcl.ecc.curves = {
|
||||
c192: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p192,
|
||||
"0x662107c8eb94364e4b2dd7ce",
|
||||
-3,
|
||||
"0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
|
||||
"0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
|
||||
"0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"),
|
||||
|
||||
c224: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p224,
|
||||
"0xe95c1f470fc1ec22d6baa3a3d5c4",
|
||||
-3,
|
||||
"0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
|
||||
"0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
|
||||
"0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
|
||||
|
||||
c256: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p256,
|
||||
"0x4319055358e8617b0c46353d039cdaae",
|
||||
-3,
|
||||
"0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
|
||||
"0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
|
||||
"0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"),
|
||||
|
||||
c384: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p384,
|
||||
"0x389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68c",
|
||||
-3,
|
||||
"0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
|
||||
"0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
|
||||
"0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")
|
||||
};
|
||||
|
||||
|
||||
/* Diffie-Hellman-like public-key system */
|
||||
sjcl.ecc._dh = function(cn) {
|
||||
sjcl.ecc[cn] = {
|
||||
publicKey: function(curve, point) {
|
||||
this._curve = curve;
|
||||
if (point instanceof Array) {
|
||||
this._point = curve.fromBits(point);
|
||||
} else {
|
||||
this._point = point;
|
||||
}
|
||||
},
|
||||
|
||||
secretKey: function(curve, exponent) {
|
||||
this._curve = curve;
|
||||
this._exponent = exponent;
|
||||
},
|
||||
|
||||
generateKeys: function(curve, paranoia) {
|
||||
if (curve === undefined) {
|
||||
curve = 256;
|
||||
}
|
||||
if (typeof curve === "number") {
|
||||
curve = sjcl.ecc.curves['c'+curve];
|
||||
if (curve === undefined) {
|
||||
throw new sjcl.exception.invalid("no such curve");
|
||||
}
|
||||
}
|
||||
var sec = sjcl.bn.random(curve.r, paranoia), pub = curve.G.mult(sec);
|
||||
return { pub: new sjcl.ecc[cn].publicKey(curve, pub),
|
||||
sec: new sjcl.ecc[cn].secretKey(curve, sec) };
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
sjcl.ecc._dh("elGamal");
|
||||
|
||||
sjcl.ecc.elGamal.publicKey.prototype = {
|
||||
kem: function(paranoia) {
|
||||
var sec = sjcl.bn.random(this._curve.r, paranoia),
|
||||
tag = this._curve.G.mult(sec).toBits(),
|
||||
key = sjcl.hash.sha256.hash(this._point.mult(sec).toBits());
|
||||
return { key: key, tag: tag };
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc.elGamal.secretKey.prototype = {
|
||||
unkem: function(tag) {
|
||||
return sjcl.hash.sha256.hash(this._curve.fromBits(tag).mult(this._exponent).toBits());
|
||||
},
|
||||
|
||||
dh: function(pk) {
|
||||
return sjcl.hash.sha256.hash(pk._point.mult(this._exponent).toBits());
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc._dh("ecdsa");
|
||||
|
||||
sjcl.ecc.ecdsa.secretKey.prototype = {
|
||||
sign: function(hash, paranoia) {
|
||||
var R = this._curve.r,
|
||||
l = R.bitLength(),
|
||||
k = sjcl.bn.random(R.sub(1), paranoia).add(1),
|
||||
r = this._curve.G.mult(k).x.mod(R),
|
||||
s = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)).inverseMod(R).mul(k).mod(R);
|
||||
return sjcl.bitArray.concat(r.toBits(l), s.toBits(l));
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc.ecdsa.publicKey.prototype = {
|
||||
verify: function(hash, rs) {
|
||||
var w = sjcl.bitArray,
|
||||
R = this._curve.r,
|
||||
l = R.bitLength(),
|
||||
r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)),
|
||||
s = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l)),
|
||||
hG = sjcl.bn.fromBits(hash).mul(s).mod(R),
|
||||
hA = r.mul(s).mod(R),
|
||||
r2 = this._curve.G.mult2(hG, hA, this._point).x;
|
||||
|
||||
if (r.equals(0) || s.equals(0) || r.greaterEquals(R) || s.greaterEquals(R) || !r2.equals(r)) {
|
||||
throw (new sjcl.exception.corrupt("signature didn't check out"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
40
core/hmac.js
40
core/hmac.js
|
@ -1,40 +0,0 @@
|
|||
/** @fileOverview HMAC implementation.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** HMAC with the specified hash function.
|
||||
* @constructor
|
||||
* @param {bitArray} key the key for HMAC.
|
||||
* @param {Object} [hash=sjcl.hash.sha256] The hash function to use.
|
||||
*/
|
||||
sjcl.misc.hmac = function (key, Hash) {
|
||||
this._hash = Hash = Hash || sjcl.hash.sha256;
|
||||
var exKey = [[],[]], i,
|
||||
bs = Hash.prototype.blockSize / 32;
|
||||
this._baseHash = [new Hash(), new Hash()];
|
||||
|
||||
if (key.length > bs) {
|
||||
key = Hash.hash(key);
|
||||
}
|
||||
|
||||
for (i=0; i<bs; i++) {
|
||||
exKey[0][i] = key[i]^0x36363636;
|
||||
exKey[1][i] = key[i]^0x5C5C5C5C;
|
||||
}
|
||||
|
||||
this._baseHash[0].update(exKey[0]);
|
||||
this._baseHash[1].update(exKey[1]);
|
||||
};
|
||||
|
||||
/** HMAC with the specified hash function. Also called encrypt since it's a prf.
|
||||
* @param {bitArray|String} data The data to mac.
|
||||
* @param {Codec} [encoding] the encoding function to use.
|
||||
*/
|
||||
sjcl.misc.hmac.prototype.encrypt = sjcl.misc.hmac.prototype.mac = function (data, encoding) {
|
||||
var w = new (this._hash)(this._baseHash[0]).update(data, encoding).finalize();
|
||||
return new (this._hash)(this._baseHash[1]).update(w).finalize();
|
||||
};
|
||||
|
171
core/ocb2.js
171
core/ocb2.js
|
@ -1,171 +0,0 @@
|
|||
/** @fileOverview OCB 2.0 implementation
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace
|
||||
* Phil Rogaway's Offset CodeBook mode, version 2.0.
|
||||
* May be covered by US and international patents.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
sjcl.mode.ocb2 = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
*/
|
||||
name: "ocb2",
|
||||
|
||||
/** Encrypt in OCB mode, version 2.0.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} plaintext The plaintext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data.
|
||||
* @param {Number} [tlen=64] the desired tag length, in bits.
|
||||
* @param [false] premac 1 if the authentication data is pre-macced with PMAC.
|
||||
* @return The encrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits.
|
||||
*/
|
||||
encrypt: function(prp, plaintext, iv, adata, tlen, premac) {
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("ocb iv must be 128 bits");
|
||||
}
|
||||
var i,
|
||||
times2 = sjcl.mode.ocb2._times2,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
checksum = [0,0,0,0],
|
||||
delta = times2(prp.encrypt(iv)),
|
||||
bi, bl,
|
||||
output = [],
|
||||
pad;
|
||||
|
||||
adata = adata || [];
|
||||
tlen = tlen || 64;
|
||||
|
||||
for (i=0; i+4 < plaintext.length; i+=4) {
|
||||
/* Encrypt a non-final block */
|
||||
bi = plaintext.slice(i,i+4);
|
||||
checksum = xor(checksum, bi);
|
||||
output = output.concat(xor(delta,prp.encrypt(xor(delta, bi))));
|
||||
delta = times2(delta);
|
||||
}
|
||||
|
||||
/* Chop out the final block */
|
||||
bi = plaintext.slice(i);
|
||||
bl = w.bitLength(bi);
|
||||
pad = prp.encrypt(xor(delta,[0,0,0,bl]));
|
||||
bi = w.clamp(xor(bi.concat([0,0,0]),pad), bl);
|
||||
|
||||
/* Checksum the final block, and finalize the checksum */
|
||||
checksum = xor(checksum,xor(bi.concat([0,0,0]),pad));
|
||||
checksum = prp.encrypt(xor(checksum,xor(delta,times2(delta))));
|
||||
|
||||
/* MAC the header */
|
||||
if (adata.length) {
|
||||
checksum = xor(checksum, premac ? adata : sjcl.mode.ocb2.pmac(prp, adata));
|
||||
}
|
||||
|
||||
return output.concat(w.concat(bi, w.clamp(checksum, tlen)));
|
||||
},
|
||||
|
||||
/** Decrypt in OCB mode.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} ciphertext The ciphertext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data.
|
||||
* @param {Number} [tlen=64] the desired tag length, in bits.
|
||||
* @param {boolean} [premac=false] true if the authentication data is pre-macced with PMAC.
|
||||
* @return The decrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits.
|
||||
* @throws {sjcl.exception.corrupt} if if the message is corrupt.
|
||||
*/
|
||||
decrypt: function(prp, ciphertext, iv, adata, tlen, premac) {
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("ocb iv must be 128 bits");
|
||||
}
|
||||
tlen = tlen || 64;
|
||||
var i,
|
||||
times2 = sjcl.mode.ocb2._times2,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
checksum = [0,0,0,0],
|
||||
delta = times2(prp.encrypt(iv)),
|
||||
bi, bl,
|
||||
len = sjcl.bitArray.bitLength(ciphertext) - tlen,
|
||||
output = [],
|
||||
pad;
|
||||
|
||||
adata = adata || [];
|
||||
|
||||
for (i=0; i+4 < len/32; i+=4) {
|
||||
/* Decrypt a non-final block */
|
||||
bi = xor(delta, prp.decrypt(xor(delta, ciphertext.slice(i,i+4))));
|
||||
checksum = xor(checksum, bi);
|
||||
output = output.concat(bi);
|
||||
delta = times2(delta);
|
||||
}
|
||||
|
||||
/* Chop out and decrypt the final block */
|
||||
bl = len-i*32;
|
||||
pad = prp.encrypt(xor(delta,[0,0,0,bl]));
|
||||
bi = xor(pad, w.clamp(ciphertext.slice(i),bl).concat([0,0,0]));
|
||||
|
||||
/* Checksum the final block, and finalize the checksum */
|
||||
checksum = xor(checksum, bi);
|
||||
checksum = prp.encrypt(xor(checksum, xor(delta, times2(delta))));
|
||||
|
||||
/* MAC the header */
|
||||
if (adata.length) {
|
||||
checksum = xor(checksum, premac ? adata : sjcl.mode.ocb2.pmac(prp, adata));
|
||||
}
|
||||
|
||||
if (!w.equal(w.clamp(checksum, tlen), w.bitSlice(ciphertext, len))) {
|
||||
throw new sjcl.exception.corrupt("ocb: tag doesn't match");
|
||||
}
|
||||
|
||||
return output.concat(w.clamp(bi,bl));
|
||||
},
|
||||
|
||||
/** PMAC authentication for OCB associated data.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} adata The authenticated data.
|
||||
*/
|
||||
pmac: function(prp, adata) {
|
||||
var i,
|
||||
times2 = sjcl.mode.ocb2._times2,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
checksum = [0,0,0,0],
|
||||
delta = prp.encrypt([0,0,0,0]),
|
||||
bi;
|
||||
|
||||
delta = xor(delta,times2(times2(delta)));
|
||||
|
||||
for (i=0; i+4<adata.length; i+=4) {
|
||||
delta = times2(delta);
|
||||
checksum = xor(checksum, prp.encrypt(xor(delta, adata.slice(i,i+4))));
|
||||
}
|
||||
|
||||
bi = adata.slice(i);
|
||||
if (w.bitLength(bi) < 128) {
|
||||
delta = xor(delta,times2(delta));
|
||||
bi = w.concat(bi,[0x80000000|0,0,0,0]);
|
||||
}
|
||||
checksum = xor(checksum, bi);
|
||||
return prp.encrypt(xor(times2(xor(delta,times2(delta))), checksum));
|
||||
},
|
||||
|
||||
/** Double a block of words, OCB style.
|
||||
* @private
|
||||
*/
|
||||
_times2: function(x) {
|
||||
return [x[0]<<1 ^ x[1]>>>31,
|
||||
x[1]<<1 ^ x[2]>>>31,
|
||||
x[2]<<1 ^ x[3]>>>31,
|
||||
x[3]<<1 ^ (x[0]>>>31)*0x87];
|
||||
}
|
||||
};
|
|
@ -1,54 +0,0 @@
|
|||
/** @fileOverview Password-based key-derivation function, version 2.0.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** Password-Based Key-Derivation Function, version 2.0.
|
||||
*
|
||||
* Generate keys from passwords using PBKDF2-HMAC-SHA256.
|
||||
*
|
||||
* This is the method specified by RSA's PKCS #5 standard.
|
||||
*
|
||||
* @param {bitArray|String} password The password.
|
||||
* @param {bitArray} salt The salt. Should have lots of entropy.
|
||||
* @param {Number} [count=1000] The number of iterations. Higher numbers make the function slower but more secure.
|
||||
* @param {Number} [length] The length of the derived key. Defaults to the
|
||||
output size of the hash function.
|
||||
* @param {Object} [Prff=sjcl.misc.hmac] The pseudorandom function family.
|
||||
* @return {bitArray} the derived key.
|
||||
*/
|
||||
sjcl.misc.pbkdf2 = function (password, salt, count, length, Prff) {
|
||||
count = count || 1000;
|
||||
|
||||
if (length < 0 || count < 0) {
|
||||
throw sjcl.exception.invalid("invalid params to pbkdf2");
|
||||
}
|
||||
|
||||
if (typeof password === "string") {
|
||||
password = sjcl.codec.utf8String.toBits(password);
|
||||
}
|
||||
|
||||
Prff = Prff || sjcl.misc.hmac;
|
||||
|
||||
var prf = new Prff(password),
|
||||
u, ui, i, j, k, out = [], b = sjcl.bitArray;
|
||||
|
||||
for (k = 1; 32 * out.length < (length || 1); k++) {
|
||||
u = ui = prf.encrypt(b.concat(salt,[k]));
|
||||
|
||||
for (i=1; i<count; i++) {
|
||||
ui = prf.encrypt(ui);
|
||||
for (j=0; j<ui.length; j++) {
|
||||
u[j] ^= ui[j];
|
||||
}
|
||||
}
|
||||
|
||||
out = out.concat(u);
|
||||
}
|
||||
|
||||
if (length) { out = b.clamp(out, length); }
|
||||
|
||||
return out;
|
||||
};
|
400
core/random.js
400
core/random.js
|
@ -1,400 +0,0 @@
|
|||
/** @fileOverview Random number generator.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Random number generator
|
||||
*
|
||||
* @description
|
||||
* <p>
|
||||
* This random number generator is a derivative of Ferguson and Schneier's
|
||||
* generator Fortuna. It collects entropy from various events into several
|
||||
* pools, implemented by streaming SHA-256 instances. It differs from
|
||||
* ordinary Fortuna in a few ways, though.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Most importantly, it has an entropy estimator. This is present because
|
||||
* there is a strong conflict here between making the generator available
|
||||
* as soon as possible, and making sure that it doesn't "run on empty".
|
||||
* In Fortuna, there is a saved state file, and the system is likely to have
|
||||
* time to warm up.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Second, because users are unlikely to stay on the page for very long,
|
||||
* and to speed startup time, the number of pools increases logarithmically:
|
||||
* a new pool is created when the previous one is actually used for a reseed.
|
||||
* This gives the same asymptotic guarantees as Fortuna, but gives more
|
||||
* entropy to early reseeds.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The entire mechanism here feels pretty klunky. Furthermore, there are
|
||||
* several improvements that should be made, including support for
|
||||
* dedicated cryptographic functions that may be present in some browsers;
|
||||
* state files in local storage; cookies containing randomness; etc. So
|
||||
* look for improvements in future versions.
|
||||
* </p>
|
||||
*/
|
||||
sjcl.random = {
|
||||
/** Generate several random words, and return them in an array
|
||||
* @param {Number} nwords The number of words to generate.
|
||||
*/
|
||||
randomWords: function (nwords, paranoia) {
|
||||
var out = [], i, readiness = this.isReady(paranoia), g;
|
||||
|
||||
if (readiness === this._NOT_READY) {
|
||||
throw new sjcl.exception.notReady("generator isn't seeded");
|
||||
} else if (readiness & this._REQUIRES_RESEED) {
|
||||
this._reseedFromPools(!(readiness & this._READY));
|
||||
}
|
||||
|
||||
for (i=0; i<nwords; i+= 4) {
|
||||
if ((i+1) % this._MAX_WORDS_PER_BURST === 0) {
|
||||
this._gate();
|
||||
}
|
||||
|
||||
g = this._gen4words();
|
||||
out.push(g[0],g[1],g[2],g[3]);
|
||||
}
|
||||
this._gate();
|
||||
|
||||
return out.slice(0,nwords);
|
||||
},
|
||||
|
||||
setDefaultParanoia: function (paranoia) {
|
||||
this._defaultParanoia = paranoia;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add entropy to the pools.
|
||||
* @param data The entropic value. Should be a 32-bit integer, array of 32-bit integers, or string
|
||||
* @param {Number} estimatedEntropy The estimated entropy of data, in bits
|
||||
* @param {String} source The source of the entropy, eg "mouse"
|
||||
*/
|
||||
addEntropy: function (data, estimatedEntropy, source) {
|
||||
source = source || "user";
|
||||
|
||||
var id,
|
||||
i, tmp,
|
||||
t = (new Date()).valueOf(),
|
||||
robin = this._robins[source],
|
||||
oldReady = this.isReady(), err = 0;
|
||||
|
||||
id = this._collectorIds[source];
|
||||
if (id === undefined) { id = this._collectorIds[source] = this._collectorIdNext ++; }
|
||||
|
||||
if (robin === undefined) { robin = this._robins[source] = 0; }
|
||||
this._robins[source] = ( this._robins[source] + 1 ) % this._pools.length;
|
||||
|
||||
switch(typeof(data)) {
|
||||
|
||||
case "number":
|
||||
if (estimatedEntropy === undefined) {
|
||||
estimatedEntropy = 1;
|
||||
}
|
||||
this._pools[robin].update([id,this._eventId++,1,estimatedEntropy,t,1,data|0]);
|
||||
break;
|
||||
|
||||
case "object":
|
||||
var objName = Object.prototype.toString.call(data);
|
||||
if (objName === "[object Uint32Array]") {
|
||||
tmp = [];
|
||||
for (i = 0; i < data.length; i++) {
|
||||
tmp.push(data[i]);
|
||||
}
|
||||
data = tmp;
|
||||
} else {
|
||||
if (objName !== "[object Array]") {
|
||||
err = 1;
|
||||
}
|
||||
for (i=0; i<data.length && !err; i++) {
|
||||
if (typeof(data[i]) != "number") {
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
if (estimatedEntropy === undefined) {
|
||||
/* horrible entropy estimator */
|
||||
estimatedEntropy = 0;
|
||||
for (i=0; i<data.length; i++) {
|
||||
tmp= data[i];
|
||||
while (tmp>0) {
|
||||
estimatedEntropy++;
|
||||
tmp = tmp >>> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._pools[robin].update([id,this._eventId++,2,estimatedEntropy,t,data.length].concat(data));
|
||||
}
|
||||
break;
|
||||
|
||||
case "string":
|
||||
if (estimatedEntropy === undefined) {
|
||||
/* English text has just over 1 bit per character of entropy.
|
||||
* But this might be HTML or something, and have far less
|
||||
* entropy than English... Oh well, let's just say one bit.
|
||||
*/
|
||||
estimatedEntropy = data.length;
|
||||
}
|
||||
this._pools[robin].update([id,this._eventId++,3,estimatedEntropy,t,data.length]);
|
||||
this._pools[robin].update(data);
|
||||
break;
|
||||
|
||||
default:
|
||||
err=1;
|
||||
}
|
||||
if (err) {
|
||||
throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");
|
||||
}
|
||||
|
||||
/* record the new strength */
|
||||
this._poolEntropy[robin] += estimatedEntropy;
|
||||
this._poolStrength += estimatedEntropy;
|
||||
|
||||
/* fire off events */
|
||||
if (oldReady === this._NOT_READY) {
|
||||
if (this.isReady() !== this._NOT_READY) {
|
||||
this._fireEvent("seeded", Math.max(this._strength, this._poolStrength));
|
||||
}
|
||||
this._fireEvent("progress", this.getProgress());
|
||||
}
|
||||
},
|
||||
|
||||
/** Is the generator ready? */
|
||||
isReady: function (paranoia) {
|
||||
var entropyRequired = this._PARANOIA_LEVELS[ (paranoia !== undefined) ? paranoia : this._defaultParanoia ];
|
||||
|
||||
if (this._strength && this._strength >= entropyRequired) {
|
||||
return (this._poolEntropy[0] > this._BITS_PER_RESEED && (new Date()).valueOf() > this._nextReseed) ?
|
||||
this._REQUIRES_RESEED | this._READY :
|
||||
this._READY;
|
||||
} else {
|
||||
return (this._poolStrength >= entropyRequired) ?
|
||||
this._REQUIRES_RESEED | this._NOT_READY :
|
||||
this._NOT_READY;
|
||||
}
|
||||
},
|
||||
|
||||
/** Get the generator's progress toward readiness, as a fraction */
|
||||
getProgress: function (paranoia) {
|
||||
var entropyRequired = this._PARANOIA_LEVELS[ paranoia ? paranoia : this._defaultParanoia ];
|
||||
|
||||
if (this._strength >= entropyRequired) {
|
||||
return 1.0;
|
||||
} else {
|
||||
return (this._poolStrength > entropyRequired) ?
|
||||
1.0 :
|
||||
this._poolStrength / entropyRequired;
|
||||
}
|
||||
},
|
||||
|
||||
/** start the built-in entropy collectors */
|
||||
startCollectors: function () {
|
||||
if (this._collectorsStarted) { return; }
|
||||
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener("load", this._loadTimeCollector, false);
|
||||
window.addEventListener("mousemove", this._mouseCollector, false);
|
||||
} else if (document.attachEvent) {
|
||||
document.attachEvent("onload", this._loadTimeCollector);
|
||||
document.attachEvent("onmousemove", this._mouseCollector);
|
||||
}
|
||||
else {
|
||||
throw new sjcl.exception.bug("can't attach event");
|
||||
}
|
||||
|
||||
this._collectorsStarted = true;
|
||||
},
|
||||
|
||||
/** stop the built-in entropy collectors */
|
||||
stopCollectors: function () {
|
||||
if (!this._collectorsStarted) { return; }
|
||||
|
||||
if (window.removeEventListener) {
|
||||
window.removeEventListener("load", this._loadTimeCollector, false);
|
||||
window.removeEventListener("mousemove", this._mouseCollector, false);
|
||||
} else if (window.detachEvent) {
|
||||
window.detachEvent("onload", this._loadTimeCollector);
|
||||
window.detachEvent("onmousemove", this._mouseCollector);
|
||||
}
|
||||
this._collectorsStarted = false;
|
||||
},
|
||||
|
||||
/* use a cookie to store entropy.
|
||||
useCookie: function (all_cookies) {
|
||||
throw new sjcl.exception.bug("random: useCookie is unimplemented");
|
||||
},*/
|
||||
|
||||
/** add an event listener for progress or seeded-ness. */
|
||||
addEventListener: function (name, callback) {
|
||||
this._callbacks[name][this._callbackI++] = callback;
|
||||
},
|
||||
|
||||
/** remove an event listener for progress or seeded-ness */
|
||||
removeEventListener: function (name, cb) {
|
||||
var i, j, cbs=this._callbacks[name], jsTemp=[];
|
||||
|
||||
/* I'm not sure if this is necessary; in C++, iterating over a
|
||||
* collection and modifying it at the same time is a no-no.
|
||||
*/
|
||||
|
||||
for (j in cbs) {
|
||||
if (cbs.hasOwnProperty(j) && cbs[j] === cb) {
|
||||
jsTemp.push(j);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<jsTemp.length; i++) {
|
||||
j = jsTemp[i];
|
||||
delete cbs[j];
|
||||
}
|
||||
},
|
||||
|
||||
/* private */
|
||||
_pools : [new sjcl.hash.sha256()],
|
||||
_poolEntropy : [0],
|
||||
_reseedCount : 0,
|
||||
_robins : {},
|
||||
_eventId : 0,
|
||||
|
||||
_collectorIds : {},
|
||||
_collectorIdNext : 0,
|
||||
|
||||
_strength : 0,
|
||||
_poolStrength : 0,
|
||||
_nextReseed : 0,
|
||||
_key : [0,0,0,0,0,0,0,0],
|
||||
_counter : [0,0,0,0],
|
||||
_cipher : undefined,
|
||||
_defaultParanoia : 6,
|
||||
|
||||
/* event listener stuff */
|
||||
_collectorsStarted : false,
|
||||
_callbacks : {progress: {}, seeded: {}},
|
||||
_callbackI : 0,
|
||||
|
||||
/* constants */
|
||||
_NOT_READY : 0,
|
||||
_READY : 1,
|
||||
_REQUIRES_RESEED : 2,
|
||||
|
||||
_MAX_WORDS_PER_BURST : 65536,
|
||||
_PARANOIA_LEVELS : [0,48,64,96,128,192,256,384,512,768,1024],
|
||||
_MILLISECONDS_PER_RESEED : 30000,
|
||||
_BITS_PER_RESEED : 80,
|
||||
|
||||
/** Generate 4 random words, no reseed, no gate.
|
||||
* @private
|
||||
*/
|
||||
_gen4words: function () {
|
||||
for (var i=0; i<4; i++) {
|
||||
this._counter[i] = this._counter[i]+1 | 0;
|
||||
if (this._counter[i]) { break; }
|
||||
}
|
||||
return this._cipher.encrypt(this._counter);
|
||||
},
|
||||
|
||||
/* Rekey the AES instance with itself after a request, or every _MAX_WORDS_PER_BURST words.
|
||||
* @private
|
||||
*/
|
||||
_gate: function () {
|
||||
this._key = this._gen4words().concat(this._gen4words());
|
||||
this._cipher = new sjcl.cipher.aes(this._key);
|
||||
},
|
||||
|
||||
/** Reseed the generator with the given words
|
||||
* @private
|
||||
*/
|
||||
_reseed: function (seedWords) {
|
||||
this._key = sjcl.hash.sha256.hash(this._key.concat(seedWords));
|
||||
this._cipher = new sjcl.cipher.aes(this._key);
|
||||
for (var i=0; i<4; i++) {
|
||||
this._counter[i] = this._counter[i]+1 | 0;
|
||||
if (this._counter[i]) { break; }
|
||||
}
|
||||
},
|
||||
|
||||
/** reseed the data from the entropy pools
|
||||
* @param full If set, use all the entropy pools in the reseed.
|
||||
*/
|
||||
_reseedFromPools: function (full) {
|
||||
var reseedData = [], strength = 0, i;
|
||||
|
||||
this._nextReseed = reseedData[0] =
|
||||
(new Date()).valueOf() + this._MILLISECONDS_PER_RESEED;
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
/* On some browsers, this is cryptographically random. So we might
|
||||
* as well toss it in the pot and stir...
|
||||
*/
|
||||
reseedData.push(Math.random()*0x100000000|0);
|
||||
}
|
||||
|
||||
for (i=0; i<this._pools.length; i++) {
|
||||
reseedData = reseedData.concat(this._pools[i].finalize());
|
||||
strength += this._poolEntropy[i];
|
||||
this._poolEntropy[i] = 0;
|
||||
|
||||
if (!full && (this._reseedCount & (1<<i))) { break; }
|
||||
}
|
||||
|
||||
/* if we used the last pool, push a new one onto the stack */
|
||||
if (this._reseedCount >= 1 << this._pools.length) {
|
||||
this._pools.push(new sjcl.hash.sha256());
|
||||
this._poolEntropy.push(0);
|
||||
}
|
||||
|
||||
/* how strong was this reseed? */
|
||||
this._poolStrength -= strength;
|
||||
if (strength > this._strength) {
|
||||
this._strength = strength;
|
||||
}
|
||||
|
||||
this._reseedCount ++;
|
||||
this._reseed(reseedData);
|
||||
},
|
||||
|
||||
_mouseCollector: function (ev) {
|
||||
var x = ev.x || ev.clientX || ev.offsetX || 0, y = ev.y || ev.clientY || ev.offsetY || 0;
|
||||
sjcl.random.addEntropy([x,y], 2, "mouse");
|
||||
},
|
||||
|
||||
_loadTimeCollector: function (ev) {
|
||||
sjcl.random.addEntropy((new Date()).valueOf(), 2, "loadtime");
|
||||
},
|
||||
|
||||
_fireEvent: function (name, arg) {
|
||||
var j, cbs=sjcl.random._callbacks[name], cbsTemp=[];
|
||||
/* TODO: there is a race condition between removing collectors and firing them */
|
||||
|
||||
/* I'm not sure if this is necessary; in C++, iterating over a
|
||||
* collection and modifying it at the same time is a no-no.
|
||||
*/
|
||||
|
||||
for (j in cbs) {
|
||||
if (cbs.hasOwnProperty(j)) {
|
||||
cbsTemp.push(cbs[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0; j<cbsTemp.length; j++) {
|
||||
cbsTemp[j](arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(function(){
|
||||
try {
|
||||
// get cryptographically strong entropy in Webkit
|
||||
var ab = new Uint32Array(32);
|
||||
crypto.getRandomValues(ab);
|
||||
sjcl.random.addEntropy(ab, 1024, "crypto.getRandomValues");
|
||||
} catch (e) {
|
||||
// no getRandomValues :-(
|
||||
}
|
||||
})();
|
165
core/sha1.js
165
core/sha1.js
|
@ -1,165 +0,0 @@
|
|||
/** @fileOverview Javascript SHA-1 implementation.
|
||||
*
|
||||
* Based on the implementation in RFC 3174, method 1, and on the SJCL
|
||||
* SHA-256 implementation.
|
||||
*
|
||||
* @author Quinn Slack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context for a SHA-1 operation in progress.
|
||||
* @constructor
|
||||
* @class Secure Hash Algorithm, 160 bits.
|
||||
*/
|
||||
sjcl.hash.sha1 = function (hash) {
|
||||
if (hash) {
|
||||
this._h = hash._h.slice(0);
|
||||
this._buffer = hash._buffer.slice(0);
|
||||
this._length = hash._length;
|
||||
} else {
|
||||
this.reset();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash a string or an array of words.
|
||||
* @static
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return {bitArray} The hash value, an array of 5 big-endian words.
|
||||
*/
|
||||
sjcl.hash.sha1.hash = function (data) {
|
||||
return (new sjcl.hash.sha1()).update(data).finalize();
|
||||
};
|
||||
|
||||
sjcl.hash.sha1.prototype = {
|
||||
/**
|
||||
* The hash's block size, in bits.
|
||||
* @constant
|
||||
*/
|
||||
blockSize: 512,
|
||||
|
||||
/**
|
||||
* Reset the hash state.
|
||||
* @return this
|
||||
*/
|
||||
reset:function () {
|
||||
this._h = this._init.slice(0);
|
||||
this._buffer = [];
|
||||
this._length = 0;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Input several words to the hash.
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return this
|
||||
*/
|
||||
update: function (data) {
|
||||
if (typeof data === "string") {
|
||||
data = sjcl.codec.utf8String.toBits(data);
|
||||
}
|
||||
var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
|
||||
ol = this._length,
|
||||
nl = this._length = ol + sjcl.bitArray.bitLength(data);
|
||||
for (i = this.blockSize+ol & -this.blockSize; i <= nl;
|
||||
i+= this.blockSize) {
|
||||
this._block(b.splice(0,16));
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Complete hashing and output the hash value.
|
||||
* @return {bitArray} The hash value, an array of 5 big-endian words. TODO
|
||||
*/
|
||||
finalize:function () {
|
||||
var i, b = this._buffer, h = this._h;
|
||||
|
||||
// Round out and push the buffer
|
||||
b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
|
||||
// Round out the buffer to a multiple of 16 words, less the 2 length words.
|
||||
for (i = b.length + 2; i & 15; i++) {
|
||||
b.push(0);
|
||||
}
|
||||
|
||||
// append the length
|
||||
b.push(Math.floor(this._length / 0x100000000));
|
||||
b.push(this._length | 0);
|
||||
|
||||
while (b.length) {
|
||||
this._block(b.splice(0,16));
|
||||
}
|
||||
|
||||
this.reset();
|
||||
return h;
|
||||
},
|
||||
|
||||
/**
|
||||
* The SHA-1 initialization vector.
|
||||
* @private
|
||||
*/
|
||||
_init:[0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0],
|
||||
|
||||
/**
|
||||
* The SHA-1 hash key.
|
||||
* @private
|
||||
*/
|
||||
_key:[0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6],
|
||||
|
||||
/**
|
||||
* The SHA-1 logical functions f(0), f(1), ..., f(79).
|
||||
* @private
|
||||
*/
|
||||
_f:function(t, b, c, d) {
|
||||
if (t <= 19) {
|
||||
return (b & c) | (~b & d);
|
||||
} else if (t <= 39) {
|
||||
return b ^ c ^ d;
|
||||
} else if (t <= 59) {
|
||||
return (b & c) | (b & d) | (c & d);
|
||||
} else if (t <= 79) {
|
||||
return b ^ c ^ d;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Circular left-shift operator.
|
||||
* @private
|
||||
*/
|
||||
_S:function(n, x) {
|
||||
return (x << n) | (x >>> 32-n);
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform one cycle of SHA-1.
|
||||
* @param {bitArray} words one block of words.
|
||||
* @private
|
||||
*/
|
||||
_block:function (words) {
|
||||
var t, tmp, a, b, c, d, e,
|
||||
w = words.slice(0),
|
||||
h = this._h,
|
||||
k = this._key;
|
||||
|
||||
a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4];
|
||||
|
||||
for (t=0; t<=79; t++) {
|
||||
if (t >= 16) {
|
||||
w[t] = this._S(1, w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]);
|
||||
}
|
||||
tmp = (this._S(5, a) + this._f(t, b, c, d) + e + w[t] +
|
||||
this._key[Math.floor(t/20)]) | 0;
|
||||
e = d;
|
||||
d = c;
|
||||
c = this._S(30, b);
|
||||
b = a;
|
||||
a = tmp;
|
||||
}
|
||||
|
||||
h[0] = (h[0]+a) |0;
|
||||
h[1] = (h[1]+b) |0;
|
||||
h[2] = (h[2]+c) |0;
|
||||
h[3] = (h[3]+d) |0;
|
||||
h[4] = (h[4]+e) |0;
|
||||
}
|
||||
};
|
216
core/sha256.js
216
core/sha256.js
|
@ -1,216 +0,0 @@
|
|||
/** @fileOverview Javascript SHA-256 implementation.
|
||||
*
|
||||
* An older version of this implementation is available in the public
|
||||
* domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
|
||||
* Stanford University 2008-2010 and BSD-licensed for liability
|
||||
* reasons.
|
||||
*
|
||||
* Special thanks to Aldo Cortesi for pointing out several bugs in
|
||||
* this code.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context for a SHA-256 operation in progress.
|
||||
* @constructor
|
||||
* @class Secure Hash Algorithm, 256 bits.
|
||||
*/
|
||||
sjcl.hash.sha256 = function (hash) {
|
||||
if (!this._key[0]) { this._precompute(); }
|
||||
if (hash) {
|
||||
this._h = hash._h.slice(0);
|
||||
this._buffer = hash._buffer.slice(0);
|
||||
this._length = hash._length;
|
||||
} else {
|
||||
this.reset();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash a string or an array of words.
|
||||
* @static
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return {bitArray} The hash value, an array of 16 big-endian words.
|
||||
*/
|
||||
sjcl.hash.sha256.hash = function (data) {
|
||||
return (new sjcl.hash.sha256()).update(data).finalize();
|
||||
};
|
||||
|
||||
sjcl.hash.sha256.prototype = {
|
||||
/**
|
||||
* The hash's block size, in bits.
|
||||
* @constant
|
||||
*/
|
||||
blockSize: 512,
|
||||
|
||||
/**
|
||||
* Reset the hash state.
|
||||
* @return this
|
||||
*/
|
||||
reset:function () {
|
||||
this._h = this._init.slice(0);
|
||||
this._buffer = [];
|
||||
this._length = 0;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Input several words to the hash.
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return this
|
||||
*/
|
||||
update: function (data) {
|
||||
if (typeof data === "string") {
|
||||
data = sjcl.codec.utf8String.toBits(data);
|
||||
}
|
||||
var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
|
||||
ol = this._length,
|
||||
nl = this._length = ol + sjcl.bitArray.bitLength(data);
|
||||
for (i = 512+ol & -512; i <= nl; i+= 512) {
|
||||
this._block(b.splice(0,16));
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Complete hashing and output the hash value.
|
||||
* @return {bitArray} The hash value, an array of 16 big-endian words.
|
||||
*/
|
||||
finalize:function () {
|
||||
var i, b = this._buffer, h = this._h;
|
||||
|
||||
// Round out and push the buffer
|
||||
b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
|
||||
|
||||
// Round out the buffer to a multiple of 16 words, less the 2 length words.
|
||||
for (i = b.length + 2; i & 15; i++) {
|
||||
b.push(0);
|
||||
}
|
||||
|
||||
// append the length
|
||||
b.push(Math.floor(this._length / 0x100000000));
|
||||
b.push(this._length | 0);
|
||||
|
||||
while (b.length) {
|
||||
this._block(b.splice(0,16));
|
||||
}
|
||||
|
||||
this.reset();
|
||||
return h;
|
||||
},
|
||||
|
||||
/**
|
||||
* The SHA-256 initialization vector, to be precomputed.
|
||||
* @private
|
||||
*/
|
||||
_init:[],
|
||||
/*
|
||||
_init:[0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19],
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SHA-256 hash key, to be precomputed.
|
||||
* @private
|
||||
*/
|
||||
_key:[],
|
||||
/*
|
||||
_key:
|
||||
[0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2],
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Function to precompute _init and _key.
|
||||
* @private
|
||||
*/
|
||||
_precompute: function () {
|
||||
var i = 0, prime = 2, factor;
|
||||
|
||||
function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
|
||||
|
||||
outer: for (; i<64; prime++) {
|
||||
for (factor=2; factor*factor <= prime; factor++) {
|
||||
if (prime % factor === 0) {
|
||||
// not a prime
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
|
||||
if (i<8) {
|
||||
this._init[i] = frac(Math.pow(prime, 1/2));
|
||||
}
|
||||
this._key[i] = frac(Math.pow(prime, 1/3));
|
||||
i++;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform one cycle of SHA-256.
|
||||
* @param {bitArray} words one block of words.
|
||||
* @private
|
||||
*/
|
||||
_block:function (words) {
|
||||
var i, tmp, a, b,
|
||||
w = words.slice(0),
|
||||
h = this._h,
|
||||
k = this._key,
|
||||
h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3],
|
||||
h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7];
|
||||
|
||||
/* Rationale for placement of |0 :
|
||||
* If a value can overflow is original 32 bits by a factor of more than a few
|
||||
* million (2^23 ish), there is a possibility that it might overflow the
|
||||
* 53-bit mantissa and lose precision.
|
||||
*
|
||||
* To avoid this, we clamp back to 32 bits by |'ing with 0 on any value that
|
||||
* propagates around the loop, and on the hash state h[]. I don't believe
|
||||
* that the clamps on h4 and on h0 are strictly necessary, but it's close
|
||||
* (for h4 anyway), and better safe than sorry.
|
||||
*
|
||||
* The clamps on h[] are necessary for the output to be correct even in the
|
||||
* common case and for short inputs.
|
||||
*/
|
||||
for (i=0; i<64; i++) {
|
||||
// load up the input word for this round
|
||||
if (i<16) {
|
||||
tmp = w[i];
|
||||
} else {
|
||||
a = w[(i+1 ) & 15];
|
||||
b = w[(i+14) & 15];
|
||||
tmp = w[i&15] = ((a>>>7 ^ a>>>18 ^ a>>>3 ^ a<<25 ^ a<<14) +
|
||||
(b>>>17 ^ b>>>19 ^ b>>>10 ^ b<<15 ^ b<<13) +
|
||||
w[i&15] + w[(i+9) & 15]) | 0;
|
||||
}
|
||||
|
||||
tmp = (tmp + h7 + (h4>>>6 ^ h4>>>11 ^ h4>>>25 ^ h4<<26 ^ h4<<21 ^ h4<<7) + (h6 ^ h4&(h5^h6)) + k[i]); // | 0;
|
||||
|
||||
// shift register
|
||||
h7 = h6; h6 = h5; h5 = h4;
|
||||
h4 = h3 + tmp | 0;
|
||||
h3 = h2; h2 = h1; h1 = h0;
|
||||
|
||||
h0 = (tmp + ((h1&h2) ^ (h3&(h1^h2))) + (h1>>>2 ^ h1>>>13 ^ h1>>>22 ^ h1<<30 ^ h1<<19 ^ h1<<10)) | 0;
|
||||
}
|
||||
|
||||
h[0] = h[0]+h0 | 0;
|
||||
h[1] = h[1]+h1 | 0;
|
||||
h[2] = h[2]+h2 | 0;
|
||||
h[3] = h[3]+h3 | 0;
|
||||
h[4] = h[4]+h4 | 0;
|
||||
h[5] = h[5]+h5 | 0;
|
||||
h[6] = h[6]+h6 | 0;
|
||||
h[7] = h[7]+h7 | 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
73
core/sjcl.js
73
core/sjcl.js
|
@ -1,73 +0,0 @@
|
|||
/** @fileOverview Javascript cryptography implementation.
|
||||
*
|
||||
* Crush to remove comments, shorten variable names and
|
||||
* generally reduce transmission size.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */
|
||||
/*global document, window, escape, unescape */
|
||||
|
||||
/** @namespace The Stanford Javascript Crypto Library, top-level namespace. */
|
||||
var sjcl = {
|
||||
/** @namespace Symmetric ciphers. */
|
||||
cipher: {},
|
||||
|
||||
/** @namespace Hash functions. Right now only SHA256 is implemented. */
|
||||
hash: {},
|
||||
|
||||
/** @namespace Key exchange functions. Right now only SRP is implemented. */
|
||||
keyexchange: {},
|
||||
|
||||
/** @namespace Block cipher modes of operation. */
|
||||
mode: {},
|
||||
|
||||
/** @namespace Miscellaneous. HMAC and PBKDF2. */
|
||||
misc: {},
|
||||
|
||||
/**
|
||||
* @namespace Bit array encoders and decoders.
|
||||
*
|
||||
* @description
|
||||
* The members of this namespace are functions which translate between
|
||||
* SJCL's bitArrays and other objects (usually strings). Because it
|
||||
* isn't always clear which direction is encoding and which is decoding,
|
||||
* the method names are "fromBits" and "toBits".
|
||||
*/
|
||||
codec: {},
|
||||
|
||||
/** @namespace Exceptions. */
|
||||
exception: {
|
||||
/** @class Ciphertext is corrupt. */
|
||||
corrupt: function(message) {
|
||||
this.toString = function() { return "CORRUPT: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @class Invalid parameter. */
|
||||
invalid: function(message) {
|
||||
this.toString = function() { return "INVALID: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @class Bug or missing feature in SJCL. */
|
||||
bug: function(message) {
|
||||
this.toString = function() { return "BUG: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @class Something isn't ready. */
|
||||
notReady: function(message) {
|
||||
this.toString = function() { return "NOT READY: "+this.message; };
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(typeof module != 'undefined' && module.exports){
|
||||
module.exports = sjcl;
|
||||
}
|
113
core/srp.js
113
core/srp.js
|
@ -1,113 +0,0 @@
|
|||
/** @fileOverview Javascript SRP implementation.
|
||||
*
|
||||
* This file contains a partial implementation of the SRP (Secure Remote
|
||||
* Password) password-authenticated key exchange protocol. Given a user
|
||||
* identity, salt, and SRP group, it generates the SRP verifier that may
|
||||
* be sent to a remote server to establish and SRP account.
|
||||
*
|
||||
* For more information, see http://srp.stanford.edu/.
|
||||
*
|
||||
* @author Quinn Slack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compute the SRP verifier from the username, password, salt, and group.
|
||||
* @class SRP
|
||||
*/
|
||||
sjcl.keyexchange.srp = {
|
||||
/**
|
||||
* Calculates SRP v, the verifier.
|
||||
* v = g^x mod N [RFC 5054]
|
||||
* @param {String} I The username.
|
||||
* @param {String} P The password.
|
||||
* @param {Object} s A bitArray of the salt.
|
||||
* @param {Object} group The SRP group. Use sjcl.keyexchange.srp.knownGroup
|
||||
to obtain this object.
|
||||
* @return {Object} A bitArray of SRP v.
|
||||
*/
|
||||
makeVerifier: function(I, P, s, group) {
|
||||
var x;
|
||||
x = this.makeX(I, P, s);
|
||||
x = sjcl.bn.fromBits(x);
|
||||
return group.g.powermod(x, group.N);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates SRP x.
|
||||
* x = SHA1(<salt> | SHA(<username> | ":" | <raw password>)) [RFC 2945]
|
||||
* @param {String} I The username.
|
||||
* @param {String} P The password.
|
||||
* @param {Object} s A bitArray of the salt.
|
||||
* @return {Object} A bitArray of SRP x.
|
||||
*/
|
||||
makeX: function(I, P, s) {
|
||||
var inner = sjcl.hash.sha1.hash(I + ':' + P);
|
||||
return sjcl.hash.sha1.hash(sjcl.bitArray.concat(s, inner));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the known SRP group with the given size (in bits).
|
||||
* @param {String} i The size of the known SRP group.
|
||||
* @return {Object} An object with "N" and "g" properties.
|
||||
*/
|
||||
knownGroup:function(i) {
|
||||
if (typeof i !== "string") { i = i.toString(); }
|
||||
if (!this._didInitKnownGroups) { this._initKnownGroups(); }
|
||||
return this._knownGroups[i];
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes bignum objects for known group parameters.
|
||||
* @private
|
||||
*/
|
||||
_didInitKnownGroups: false,
|
||||
_initKnownGroups:function() {
|
||||
var i, size, group;
|
||||
for (i=0; i < this._knownGroupSizes.length; i++) {
|
||||
size = this._knownGroupSizes[i].toString();
|
||||
group = this._knownGroups[size];
|
||||
group.N = new sjcl.bn(group.N);
|
||||
group.g = new sjcl.bn(group.g);
|
||||
}
|
||||
this._didInitKnownGroups = true;
|
||||
},
|
||||
|
||||
_knownGroupSizes: [1024, 1536, 2048],
|
||||
_knownGroups: {
|
||||
1024: {
|
||||
N: "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" +
|
||||
"9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" +
|
||||
"8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" +
|
||||
"7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" +
|
||||
"FD5138FE8376435B9FC61D2FC0EB06E3",
|
||||
g:2
|
||||
},
|
||||
|
||||
1536: {
|
||||
N: "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961" +
|
||||
"4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843" +
|
||||
"80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B" +
|
||||
"E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5" +
|
||||
"6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A" +
|
||||
"F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E" +
|
||||
"8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB",
|
||||
g: 2
|
||||
},
|
||||
|
||||
2048: {
|
||||
N: "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294" +
|
||||
"3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D" +
|
||||
"CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB" +
|
||||
"D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74" +
|
||||
"7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A" +
|
||||
"436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D" +
|
||||
"5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73" +
|
||||
"03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" +
|
||||
"94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" +
|
||||
"9E4AFF73",
|
||||
g: 2
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 669 B |
179
demo/example.css
179
demo/example.css
|
@ -1,179 +0,0 @@
|
|||
* {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
font-family: Arial, Helvetica, FreeSans, sans;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
background: #eee;
|
||||
padding: 5px;
|
||||
margin-bottom: 0.6em;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.header {
|
||||
width: 650px;
|
||||
margin: 0px auto 1em;
|
||||
}
|
||||
|
||||
p+p {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.explanation {
|
||||
color: #555;
|
||||
margin-top: 0.3em;
|
||||
}
|
||||
|
||||
.section+.section, .explanation+.section {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.hex {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.hex, .base64, #ciphertext {
|
||||
font-family: 'Courier', mono;
|
||||
}
|
||||
|
||||
.wide, textarea {
|
||||
width: 100%;
|
||||
margin: 0px -4px;
|
||||
font-size: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
textarea+*, .wide+* {
|
||||
margin-top: 0.3em;
|
||||
}
|
||||
|
||||
/* bulk object placement */
|
||||
#theForm {
|
||||
position: relative;
|
||||
width: 940px;
|
||||
margin: 0px auto;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.column {
|
||||
top: 0px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.box {
|
||||
border: 2px solid #999;
|
||||
padding: 7px;
|
||||
margin-bottom: 20px;
|
||||
-moz-border-radius: 7px;
|
||||
-webkit-border-radius: 7px;
|
||||
}
|
||||
|
||||
#cmode { position: absolute; left: 640px; }
|
||||
#ctexts { position: absolute; left: 320px; }
|
||||
|
||||
.floatright {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
color: #282;
|
||||
}
|
||||
|
||||
a.random, #buttons a { text-decoration: none; }
|
||||
a.random:hover, a.random:focus { text-decoration: underline; }
|
||||
|
||||
h2 {
|
||||
margin: -7px -7px 3px -7px;
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
color: white;
|
||||
background: #999;
|
||||
}
|
||||
|
||||
#pplaintext { border-color: #f65; }
|
||||
#pplaintext h2 { background: #f65; }
|
||||
|
||||
#ppassword { border-color: #4a4; }
|
||||
#ppassword h2 { background: #4a4; }
|
||||
|
||||
#pciphertext { border-color: #78f; }
|
||||
#pciphertext h2 { background: #78f; }
|
||||
|
||||
#buttons { text-align: center; margin-top: -20px; }
|
||||
|
||||
a#doPbkdf2, a#encrypt, a#decrypt {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
height: 43px;
|
||||
padding-top: 20px;
|
||||
width: 50px;
|
||||
background: url('alpha-arrow.png') no-repeat bottom center;
|
||||
vertical-align: middle;
|
||||
border: none;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.turnDown {
|
||||
display: inline-block;
|
||||
padding-bottom: 3px;
|
||||
-moz-transform: rotate(90deg);
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.turnUp {
|
||||
display: inline-block;
|
||||
padding-bottom: 3px;
|
||||
-moz-transform: rotate(-90deg);
|
||||
-webkit-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.buttons a.disabled {
|
||||
background-color: #ccc ! important;
|
||||
cursor: inherit ! important;
|
||||
}
|
||||
|
||||
a#encrypt { background-color: #f65; margin-bottom: 2px; }
|
||||
a#encrypt:hover, a#encrypt:focus { background-color: #f76; }
|
||||
a#encrypt:active { background-color: #f87; }
|
||||
|
||||
a#decrypt {
|
||||
height: 36px;
|
||||
padding-top: 27px;
|
||||
background: url('alpha-arrow.png') no-repeat top center;
|
||||
background-color: #78f;
|
||||
margin-top: 2px;
|
||||
}
|
||||
a#decrypt:hover { background-color: #89f; }
|
||||
a#decrypt:focus { background-color: #89f; }
|
||||
a#decrypt:active { background-color: #9af; }
|
||||
|
||||
#ppassword, #pkey, #pmode, #pplaintext, #pciphertext {
|
||||
-moz-border-radius: 7px;
|
||||
-webkit-border-radius: 7px;
|
||||
}
|
||||
input[type='text'], input[type='password'], textarea {
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
font-size: inherit;
|
||||
border: 1px solid #444;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
input[type='text']:focus, input[type='password']:focus, textarea:focus {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
input[type="radio"], input[type="checkbox"] {
|
||||
position: relative;
|
||||
top: 0.15em;
|
||||
margin-right: -0.15em;
|
||||
}
|
153
demo/example.js
153
demo/example.js
|
@ -1,153 +0,0 @@
|
|||
/* keep track of which salts have been used. */
|
||||
var form, usedIvs = {'':1}, usedSalts = {'':1};
|
||||
|
||||
/* enter actions */
|
||||
var enterActions = {
|
||||
password: doPbkdf2,
|
||||
salt: doPbkdf2,
|
||||
iter: doPbkdf2
|
||||
};
|
||||
|
||||
function loaded() {
|
||||
form = new formHandler('theForm', enterActions);
|
||||
form._extendedKey = [];
|
||||
sjcl.random.startCollectors();
|
||||
document.getElementById("password").focus();
|
||||
}
|
||||
|
||||
/* there's probaby a better way to tell the user something, but oh well */
|
||||
function error(x) {
|
||||
alert(x);
|
||||
}
|
||||
|
||||
/* compute PBKDF2 on the password. */
|
||||
function doPbkdf2(decrypting) {
|
||||
var v = form.get(), salt=v.salt, key, hex = sjcl.codec.hex.fromBits, p={},
|
||||
password = v.password;
|
||||
|
||||
p.iter = v.iter;
|
||||
|
||||
if (password.length == 0) {
|
||||
if (decrypting) { error("Can't decrypt: need a password!"); }
|
||||
return;
|
||||
}
|
||||
|
||||
if (salt.length === 0 && decrypting) {
|
||||
error("Can't decrypt: need a salt for PBKDF2!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (decrypting || !v.freshsalt || !usedSalts[v.salt]) {
|
||||
p.salt = v.salt;
|
||||
}
|
||||
|
||||
p = sjcl.misc.cachedPbkdf2(password, p);
|
||||
form._extendedKey = p.key;
|
||||
v.key = p.key.slice(0, v.keysize/32);
|
||||
v.salt = p.salt;
|
||||
|
||||
form.set(v);
|
||||
form.plaintext.el.select();
|
||||
}
|
||||
/* Encrypt a message */
|
||||
function doEncrypt() {
|
||||
var v = form.get(), iv = v.iv, password = v.password, key = v.key, adata = v.adata, aes, plaintext=v.plaintext, rp = {}, ct, p;
|
||||
|
||||
if (plaintext === '' && v.ciphertext.length) { return; }
|
||||
if (key.length == 0 && password.length == 0) {
|
||||
error("need a password or key!");
|
||||
return;
|
||||
}
|
||||
|
||||
p = { adata:v.adata,
|
||||
iter:v.iter,
|
||||
mode:v.mode,
|
||||
ts:parseInt(v.tag),
|
||||
ks:parseInt(v.keysize) };
|
||||
if (!v.freshiv || !usedIvs[v.iv]) { p.iv = v.iv; }
|
||||
if (!v.freshsalt || !usedSalts[v.salt]) { p.salt = v.salt; }
|
||||
ct = sjcl.encrypt(password || key, plaintext, p, rp).replace(/,/g,",\n");
|
||||
|
||||
v.iv = rp.iv;
|
||||
usedIvs[rp.iv] = 1;
|
||||
if (rp.salt) {
|
||||
v.salt = rp.salt;
|
||||
usedSalts[rp.salt] = 1;
|
||||
}
|
||||
v.key = rp.key;
|
||||
|
||||
if (v.json) {
|
||||
v.ciphertext = ct;
|
||||
v.adata = '';
|
||||
} else {
|
||||
v.ciphertext = ct.match(/"ct":"([^"]*)"/)[1]; //"
|
||||
}
|
||||
|
||||
v.plaintext = '';
|
||||
|
||||
form.set(v);
|
||||
form.ciphertext.el.select();
|
||||
}
|
||||
|
||||
/* Decrypt a message */
|
||||
function doDecrypt() {
|
||||
var v = form.get(), iv = v.iv, key = v.key, adata = v.adata, aes, ciphertext=v.ciphertext, rp = {};
|
||||
|
||||
if (ciphertext.length === 0) { return; }
|
||||
if (!v.password && !v.key.length) {
|
||||
error("Can't decrypt: need a password or key!"); return;
|
||||
}
|
||||
|
||||
if (ciphertext.match("{")) {
|
||||
/* it's jsonized */
|
||||
try {
|
||||
v.plaintext = sjcl.decrypt(v.password || v.key, ciphertext, {}, rp);
|
||||
} catch(e) {
|
||||
error("Can't decrypt: "+e);
|
||||
return;
|
||||
}
|
||||
v.mode = rp.mode;
|
||||
v.iv = rp.iv;
|
||||
v.adata = rp.adata;
|
||||
if (v.password) {
|
||||
v.salt = rp.salt;
|
||||
v.iter = rp.iter;
|
||||
v.keysize = rp.ks;
|
||||
v.tag = rp.ts;
|
||||
}
|
||||
v.key = rp.key;
|
||||
v.ciphertext = "";
|
||||
document.getElementById('plaintext').select();
|
||||
} else {
|
||||
/* it's raw */
|
||||
ciphertext = sjcl.codec.base64.toBits(ciphertext);
|
||||
if (iv.length === 0) {
|
||||
error("Can't decrypt: need an IV!"); return;
|
||||
}
|
||||
if (key.length === 0) {
|
||||
if (v.password.length) {
|
||||
doPbkdf2(true);
|
||||
key = v.key;
|
||||
}
|
||||
}
|
||||
aes = new sjcl.cipher.aes(key);
|
||||
|
||||
try {
|
||||
v.plaintext = sjcl.codec.utf8String.fromBits(sjcl.mode[v.mode].decrypt(aes, ciphertext, iv, v.adata, v.tag));
|
||||
v.ciphertext = "";
|
||||
document.getElementById('plaintext').select();
|
||||
} catch (e) {
|
||||
error("Can't decrypt: " + e);
|
||||
}
|
||||
}
|
||||
form.set(v);
|
||||
}
|
||||
|
||||
function extendKey(size) {
|
||||
form.key.set(form._extendedKey.slice(0,size));
|
||||
}
|
||||
|
||||
function randomize(field, words, paranoia) {
|
||||
form[field].set(sjcl.random.randomWords(words, paranoia));
|
||||
if (field == 'salt') { form.key.set([]); }
|
||||
}
|
137
demo/form.js
137
demo/form.js
|
@ -1,137 +0,0 @@
|
|||
/* Hackish form handling system. */
|
||||
function hasClass(e, cl) {
|
||||
return (" "+e.className+" ").match(" "+cl+" ");
|
||||
}
|
||||
|
||||
function stopPropagation(e) {
|
||||
e.preventDefault && e.preventDefault();
|
||||
e.cancelBubble = true;
|
||||
}
|
||||
|
||||
/* proxy for a form object, with appropriate encoder/decoder */
|
||||
function formElement(el) {
|
||||
this.el = el;
|
||||
}
|
||||
formElement.prototype = {
|
||||
get: function() {
|
||||
var el = this.el;
|
||||
if (el.type == "checkbox") {
|
||||
return el.checked;
|
||||
} else if (hasClass(el, "numeric")) {
|
||||
return parseInt(el.value);
|
||||
} else if (hasClass(el, "hex")) {
|
||||
return sjcl.codec.hex.toBits(el.value);
|
||||
} else if (hasClass(el, "base64")) {
|
||||
return sjcl.codec.base64.toBits(el.value);
|
||||
} else {
|
||||
return el.value;
|
||||
}
|
||||
},
|
||||
|
||||
set: function(x) {
|
||||
var el = this.el;
|
||||
if (el.type == "checkbox") {
|
||||
el.checked = x; return;
|
||||
} else if (hasClass(el, "hex")) {
|
||||
if (typeof x !== 'string') {
|
||||
x = sjcl.codec.hex.fromBits(x);
|
||||
}
|
||||
x = x.toUpperCase().replace(/ /g,'').replace(/(.{8})/g, "$1 ").replace(/ $/, '');
|
||||
} else if (hasClass(el, "base64")) {
|
||||
if (typeof x !== 'string') {
|
||||
x = sjcl.codec.base64.fromBits(x);
|
||||
}
|
||||
x = x.replace(/\s/g,'').replace(/(.{32})/g, "$1\n").replace(/\n$/, '');
|
||||
}
|
||||
el.value = x;
|
||||
}
|
||||
}
|
||||
|
||||
function radioGroup(name) {
|
||||
this.name = name;
|
||||
}
|
||||
radioGroup.prototype = {
|
||||
get: function() {
|
||||
var els = document.getElementsByName(this.name), i;
|
||||
for (i=0; i<els.length; i++) {
|
||||
if (els[i].checked) {
|
||||
return els[i].value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
set: function(x) {
|
||||
var els = document.getElementsByName(this.name), i;
|
||||
for (i=0; i<els.length; i++) {
|
||||
els[i].checked = (els[i].value == x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formHandler(formName, enterActions) {
|
||||
var i, els = [], tmp, name;
|
||||
this._elNames = [];
|
||||
|
||||
tmp = document.getElementById(formName).getElementsByTagName('input');
|
||||
for (i=0; i<tmp.length; i++) { els.push(tmp[i]); }
|
||||
|
||||
tmp = document.getElementById(formName).getElementsByTagName('textarea');
|
||||
for (i=0; i<tmp.length; i++) { els.push(tmp[i]); }
|
||||
|
||||
for (i=0; i<els.length; i++) {
|
||||
name = els[i].name || els[i].id;
|
||||
|
||||
/* enforce numeric properties of element */
|
||||
els[i].onkeypress = (function(e) {
|
||||
return function(ev) {
|
||||
ev = ev || window.event;
|
||||
var key = ev.keyCode || ev.which,
|
||||
keyst = String.fromCharCode(ev.charCode || ev.keyCode),
|
||||
ente = enterActions[e.name||e.id];
|
||||
|
||||
if (ev.ctrlKey || ev.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
(key == 13) && ente && ente();
|
||||
|
||||
if (hasClass(e, 'numeric') && ev.charCode && !keyst.match(/[0-9]/)) {
|
||||
stopPropagation(ev); return false;
|
||||
} else if (hasClass(e, 'hex') && ev.charCode && !keyst.match(/[0-9a-fA-F ]/)) {
|
||||
stopPropagation(ev); return false;
|
||||
}
|
||||
}
|
||||
})(els[i]);
|
||||
|
||||
if (els[i].type == 'radio') {
|
||||
if (this[name] === undefined) {
|
||||
this[name] = new radioGroup(name);
|
||||
this._elNames.push(name);
|
||||
}
|
||||
} else {
|
||||
/* code to get the value of an element */
|
||||
this[name] = new formElement(els[i]);
|
||||
this._elNames.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formHandler.prototype = {
|
||||
get:function() {
|
||||
var i, out = {}, en = this._elNames;
|
||||
for (i=0; i<en.length; i++) {
|
||||
out[en[i]] = this[en[i]].get();
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
set:function(o) {
|
||||
var i;
|
||||
for (i in o) {
|
||||
if (o.hasOwnProperty(i) && this.hasOwnProperty(i)) {
|
||||
this[i].set(o[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
208
demo/index.html
208
demo/index.html
|
@ -1,208 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>SJCL demo</title>
|
||||
<link rel="stylesheet" type="text/css" href="example.css"/>
|
||||
<script type="text/javascript" src="../sjcl.js"></script>
|
||||
<script type="text/javascript" src="form.js"></script>
|
||||
<script type="text/javascript" src="example.js"></script>
|
||||
</head>
|
||||
<body onload="loaded()">
|
||||
<h1>SJCL demo</h1>
|
||||
|
||||
<div class="header">
|
||||
<p>This page is a demo of the Stanford Javascript Crypto Library. To get started, just type in a password in the left pane and a secret message in the middle pane, then click "encrypt". Encryption takes place in your browser and we never see the plaintext.</p>
|
||||
|
||||
<p>SJCL has lots of other options, many of which are shown in the grey boxes.</p>
|
||||
</div>
|
||||
|
||||
<form id="theForm" onsubmit="return false;">
|
||||
<div class="column" id="ckey">
|
||||
<!-- Password and pbkdf2 parameters -->
|
||||
<div class="box" id="ppassword">
|
||||
<h2>Password</h2>
|
||||
<div class="section">
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" class="wide" name="password" id="password" autocomplete="off" tabindex="1"/>
|
||||
<p class="explanation">
|
||||
Choose a strong, random password.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box" id="pkey">
|
||||
<h2>Key Derivation</h2>
|
||||
<div class="section">
|
||||
<div>
|
||||
<label for="salt"">Salt:</label>
|
||||
<a class="random floatright" href="javascript:randomize('salt',2,0)">random</a>
|
||||
</div>
|
||||
<input type="text" id="salt" class="wide hex" autocomplete="off" size="17" maxlength="35"/>
|
||||
<input type="checkbox" name="freshsalt" id="freshsalt" autocomplete="off" checked="checked"/>
|
||||
<label for="freshsalt">Use fresh random salt for each new password</label>
|
||||
<p class="explanation">
|
||||
Salt adds more variability to your key, and prevents attackers
|
||||
from using <a href="http://en.wikipedia.org/wiki/Rainbow_table">rainbow tables</a> to attack it.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<label for="iter">Strengthen by a factor of:</label>
|
||||
<input type="text" name="iter" id="iter" value="1000" class="numeric" size="5" maxlength="5" autocomplete="off"/>
|
||||
<p class="explanation">
|
||||
Strengthening makes it slower to compute the key corresponding to your
|
||||
password. This makes it take much longer for an attacker to guess it.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
Key size:
|
||||
<input type="radio" name="keysize" value="128" id="key128" checked="checked" autocomplete="off" onclick="extendKey(4)"/>
|
||||
<label for="key128">128</label>
|
||||
<input type="radio" name="keysize" value="192" id="key192" autocomplete="off" onclick="extendKey(6)"/>
|
||||
<label for="key192">192</label>
|
||||
<input type="radio" name="keysize" value="256" id="key256" autocomplete="off" onclick="extendKey(8)"/>
|
||||
<label for="key256">256</label>
|
||||
<p class="explanation">
|
||||
128 bits should be secure enough, but you can generate a longer
|
||||
key if you wish.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- cipher key -->
|
||||
<div class="section">
|
||||
<div>
|
||||
<label for="key">Key:</label>
|
||||
<!--
|
||||
<a class="random floatright" href="javascript:randomizeKey()">random</a>
|
||||
-->
|
||||
</div>
|
||||
<textarea id="key" name="key" class="hex" rows="2" autocomplete="off"></textarea>
|
||||
<p class="explanation">
|
||||
This key is computed from your password, salt and strengthening factor. It
|
||||
will be used internally by the cipher. Instead of using a password, you can
|
||||
enter a key here directly. If you do, it should be 32, 48 or 64 hexadecimal
|
||||
digits (128, 192 or 256 bits).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- mode controls -->
|
||||
<div class="column" id="cmode">
|
||||
<div class="box">
|
||||
<h2>Cipher Parameters</h2>
|
||||
<p class="explanation">
|
||||
SJCL encrypts your data with the <a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard"><acronym title="Advanced Encryption Standard">AES</acronym></a> block cipher.
|
||||
</p>
|
||||
<div class="section">
|
||||
Cipher mode:
|
||||
<input type="radio" name="mode" value="ccm" id="ccm" checked="checked" autocomplete="off"/>
|
||||
<label for="ccm"><acronym title="Counter mode with Cipher block chaining Message authentication code">CCM</acronym></label>
|
||||
<input type="radio" name="mode" value="ocb2" id="ocb2" autocomplete="off"/>
|
||||
<label for="ocb2"><acronym title="Offset CodeBook mode, version 2.0">OCB2</acronym></label>
|
||||
<p class="explanation">
|
||||
The cipher mode is a standard for how to use AES and other
|
||||
algorithms to encrypt and authenticate your message.
|
||||
<a href="http://en.wikipedia.org/wiki/OCB_mode">OCB2 mode</a>
|
||||
is slightly faster and has more features, but
|
||||
<a href="http://en.wikipedia.org/wiki/CCM_mode">CCM mode</a> has wider
|
||||
support because it is not patented.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div>
|
||||
<label for="iv">Initialization vector:</label>
|
||||
<a class="random floatright" href="javascript:randomize('iv',4,0)">random</a>
|
||||
</div>
|
||||
<input type="text" name="iv" id="iv" class="wide hex" size="32" maxlength="35" autocomplete="off"/>
|
||||
<input type="checkbox" id="freshiv" autocomplete="off" checked="checked"/>
|
||||
<label for="freshiv">Choose a new random IV for every message.</label>
|
||||
<p class="explanation">
|
||||
The IV needs to be different for every message you send. It adds
|
||||
randomness to your message, so that the same message will look
|
||||
different each time you send it.
|
||||
</p>
|
||||
<p class="explanation">
|
||||
Be careful: CCM mode doesn't use
|
||||
the whole IV, so changing just part of it isn't enough.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
Authentication strength:
|
||||
<input type="radio" name="tag" value="64" id="tag64" autocomplete="off" checked="checked"/>
|
||||
<label for="tag64">64</label>
|
||||
<input type="radio" name="tag" value="96" id="tag96" autocomplete="off"/>
|
||||
<label for="tag96">96</label>
|
||||
<input type="radio" name="tag" value="128" id="tag128" autocomplete="off"/>
|
||||
<label for="tag128">128</label>
|
||||
<p class="explanation">
|
||||
SJCL adds a an authentication tag to your message to make sure
|
||||
nobody changes it. The longer the authentication tag, the harder it is
|
||||
for somebody to change your encrypted message without you noticing. 64
|
||||
bits is probably enough.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<input type="checkbox" name="json" id="json" autocomplete="off" checked="checked"/>
|
||||
<label for="json">Send the parameters and authenticated data along
|
||||
with the message.</label>
|
||||
<p class="explanation">
|
||||
These parameters are required to decrypt your message later. If the
|
||||
person you're sending the message to knows them, you don't need to send
|
||||
them so your message will be shorter.
|
||||
</p>
|
||||
<p class="explanation">
|
||||
Default parameters won't be sent. Your password won't be sent, either.
|
||||
The salt and iv will be encoded in base64 instead of hex, so they'll
|
||||
look different from what's in the box.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column" id="ctexts">
|
||||
<div id="pplaintext" class="box">
|
||||
<h2>Plaintext</h2>
|
||||
<div class="section">
|
||||
<label for="plaintext">Secret message:</label>
|
||||
<textarea id="plaintext" autocomplete="off" rows="5" tabindex="2"></textarea>
|
||||
<div class="explanation">
|
||||
This message will be encrypted, so that nobody can read it or change it
|
||||
without your password.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<label for="adata">Authenticated data:</label>
|
||||
<textarea id="adata" autocomplete="off" tabindex="3"></textarea>
|
||||
<div class="explanation">
|
||||
This auxilliary message isn't secret, but its integrity will be checked
|
||||
along with the integrity of the message.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="buttons">
|
||||
<a href="javascript:doEncrypt()" id="encrypt" tabindex="4"><span class="turnDown">encrypt</span></a>
|
||||
<a href="javascript:doDecrypt()" id="decrypt" tabindex="6"><span class="turnUp">decrypt</span></a>
|
||||
</div>
|
||||
|
||||
<div id="pciphertext" class="box">
|
||||
<h2>Ciphertext</h2>
|
||||
<label for="ciphertext">Ciphertext:</label>
|
||||
<textarea id="ciphertext" autocomplete="off" rows="7" tabindex="5"></textarea>
|
||||
<div class="explanation">
|
||||
Your message, encrypted and authenticated so that nobody can read it
|
||||
or change it without your password.
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -1,183 +0,0 @@
|
|||
======================================================================
|
||||
|
||||
DESCRIPTION:
|
||||
|
||||
This is the source code for JsDoc Toolkit, an automatic documentation
|
||||
generation tool for JavaScript. It is written in JavaScript and is run
|
||||
from a command line (or terminal) using Java and Mozilla's Rhino
|
||||
JavaScript runtime engine.
|
||||
|
||||
Using this tool you can automatically turn JavaDoc-like comments in
|
||||
your JavaScript source code into published output files, such as HTML
|
||||
or XML.
|
||||
|
||||
For more information, to report a bug, or to browse the technical
|
||||
documentation for this tool please visit the official JsDoc Toolkit
|
||||
project homepage at http://code.google.com/p/jsdoc-toolkit/
|
||||
|
||||
For the most up-to-date documentation on JsDoc Toolkit see the
|
||||
official wiki at http://code.google.com/p/jsdoc-toolkit/w/list
|
||||
|
||||
======================================================================
|
||||
|
||||
REQUIREMENTS:
|
||||
|
||||
JsDoc Toolkit is known to work with:
|
||||
java version "1.6.0_03"
|
||||
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
|
||||
on Windows XP,
|
||||
and java version "1.5.0_19"
|
||||
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_19-b02-304)
|
||||
on Mac OS X 10.5.
|
||||
|
||||
Other versions of java may or may not work with JsDoc Toolkit.
|
||||
|
||||
======================================================================
|
||||
|
||||
USAGE:
|
||||
|
||||
Running JsDoc Toolkit requires you to have Java installed on your
|
||||
computer. For more information see http://www.java.com/getjava/
|
||||
|
||||
Before running the JsDoc Toolkit app you should change your current
|
||||
working directory to the jsdoc-toolkit folder. Then follow the
|
||||
examples below, or as shown on the project wiki.
|
||||
|
||||
On a computer running Windows a valid command line to run JsDoc
|
||||
Toolkit might look like this:
|
||||
|
||||
> java -jar jsrun.jar app\run.js -a -t=templates\jsdoc mycode.js
|
||||
|
||||
On Mac OS X or Linux the same command would look like this:
|
||||
|
||||
$ java -jar jsrun.jar app/run.js -a -t=templates/jsdoc mycode.js
|
||||
|
||||
The above assumes your current working directory contains jsrun.jar,
|
||||
the "app" and "templates" subdirectories from the standard JsDoc
|
||||
Toolkit distribution and that the relative path to the code you wish
|
||||
to document is "mycode.js".
|
||||
|
||||
The output documentation files will be saved to a new directory named
|
||||
"out" (by default) in the current directory, or if you specify a
|
||||
-d=somewhere_else option, to the somewhere_else directory.
|
||||
|
||||
For help (usage notes) enter this on the command line:
|
||||
|
||||
$ java -jar jsrun.jar app/run.js --help
|
||||
|
||||
More information about the various command line options used by JsDoc
|
||||
Toolkit are available on the project wiki.
|
||||
|
||||
======================================================================
|
||||
|
||||
RUNNING VIA SHELL SCRIPT
|
||||
|
||||
Avi Deitcher has contributed the file jsrun.sh with the following usage notes:
|
||||
|
||||
A script to simplify running jsdoc from the command-line, especially when
|
||||
running from within a development or build environment such as ant.
|
||||
|
||||
Normally, to run jsdoc, you need a command-line as the following:
|
||||
java -Djsdoc.dir=/some/long/dir/path/to/jsdoc -jar
|
||||
/some/long/dir/path/to/jsdoc/jsrun.jar /some/long/dir/path/to/jsdoc/app/run.js
|
||||
-t=template -r=4 /some/long/dir/path/to/my/src/code
|
||||
|
||||
This can get tedious to redo time and again, and difficult to use from within a build environment.
|
||||
|
||||
To simplify the process, jsrun.sh will automatically run this path, as well as passing through any arguments.
|
||||
|
||||
Usage: jsrun.sh <run.js arguments>
|
||||
|
||||
All <run.js arguments> will be passed through.
|
||||
Additionally, jsrun.sh will take the following actions:
|
||||
1) If the environment variable JSDOCDIR is set, it will add
|
||||
"-Djsdoc.dir=$JSDOCDIR" to the command-line
|
||||
2) If the environment variable JSDOCTEMPLATEDIR is set, it will add
|
||||
"-Djsdoc.template.dir=$JSDOCTEMPLATEDIR" to the command-line
|
||||
3) java with the appropriate path to jsrun.jar and run.js will be instantiated
|
||||
|
||||
If not variables are set, it is assumed that the path to jsrun.jar and app/ is in the current working directory.
|
||||
|
||||
Example:
|
||||
# jsrun.sh ./src/
|
||||
Assuming JSDOCDIR=/some/path/to/my/jsdoc will cause the following command to
|
||||
execute:
|
||||
java -Djsdoc.dir=/some/path/to/my/jsdoc -jar /some/path/to/my/jsdoc/jsrun.jar
|
||||
/some/path/to/my/jsdoc/app/run.js ./src/
|
||||
|
||||
======================================================================
|
||||
|
||||
TESTING:
|
||||
|
||||
To run the suite of unit tests included with JsDoc Toolkit enter this
|
||||
on the command line:
|
||||
|
||||
$ java -jar jsrun.jar app/run.js -T
|
||||
|
||||
To see a dump of the internal data structure that JsDoc Toolkit has
|
||||
built from your source files use this command:
|
||||
|
||||
$ java -jar jsrun.jar app/run.js mycode.js -Z
|
||||
|
||||
======================================================================
|
||||
|
||||
LICENSE:
|
||||
|
||||
JSDoc.pm
|
||||
|
||||
This project is based on the JSDoc.pm tool, created by Michael
|
||||
Mathews and Gabriel Reid. More information on JsDoc.pm can
|
||||
be found on the JSDoc.pm homepage: http://jsdoc.sourceforge.net/
|
||||
|
||||
Complete documentation on JsDoc Toolkit can be found on the project
|
||||
wiki at http://code.google.com/p/jsdoc-toolkit/w/list
|
||||
|
||||
Rhino
|
||||
|
||||
Rhino (JavaScript in Java) is open source and licensed by Mozilla
|
||||
under the MPL 1.1 or later/GPL 2.0 or later licenses, the text of
|
||||
which is available at http://www.mozilla.org/MPL/
|
||||
|
||||
You can obtain the source code for Rhino from the Mozilla web site at
|
||||
http://www.mozilla.org/rhino/download.html
|
||||
|
||||
JsDoc Toolkit is a larger work that uses the Rhino JavaScript engine
|
||||
but is not derived from it in any way. The Rhino library is used
|
||||
without modification and without any claims whatsoever.
|
||||
|
||||
The Rhino Debugger
|
||||
|
||||
You can obtain more information about the Rhino Debugger from the
|
||||
Mozilla web site at http://www.mozilla.org/rhino/debugger.html
|
||||
|
||||
JsDoc Toolkit is a larger work that uses the Rhino Debugger but
|
||||
is not derived from it in any way. The Rhino Debugger is used
|
||||
without modification and without any claims whatsoever.
|
||||
|
||||
JsDoc Toolkit
|
||||
|
||||
All code specific to JsDoc Toolkit are free, open source and licensed
|
||||
for use under the X11/MIT License.
|
||||
|
||||
JsDoc Toolkit is Copyright (c)2009 Michael Mathews <micmath@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms below.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions: The above copyright notice and this
|
||||
permission notice must be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,33 +0,0 @@
|
|||
IO.include("frame/Opt.js");
|
||||
IO.include("frame/Chain.js");
|
||||
IO.include("frame/Link.js");
|
||||
IO.include("frame/String.js");
|
||||
IO.include("frame/Hash.js");
|
||||
IO.include("frame/Namespace.js");
|
||||
//IO.include("frame/Reflection.js");
|
||||
|
||||
/** A few helper functions to make life a little easier. */
|
||||
|
||||
function defined(o) {
|
||||
return (o !== undefined);
|
||||
}
|
||||
|
||||
function copy(o) { // todo check for circular refs
|
||||
if (o == null || typeof(o) != 'object') return o;
|
||||
var c = new o.constructor();
|
||||
for(var p in o) c[p] = copy(o[p]);
|
||||
return c;
|
||||
}
|
||||
|
||||
function isUnique(arr) {
|
||||
var l = arr.length;
|
||||
for(var i = 0; i < l; i++ ) {
|
||||
if (arr.lastIndexOf(arr[i]) > i) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the given string with all regex meta characters backslashed. */
|
||||
RegExp.escapeMeta = function(str) {
|
||||
return str.replace(/([$^\\\/()|?+*\[\]{}.-])/g, "\\$1");
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
/**@constructor*/
|
||||
function ChainNode(object, link) {
|
||||
this.value = object;
|
||||
this.link = link; // describes this node's relationship to the previous node
|
||||
}
|
||||
|
||||
/**@constructor*/
|
||||
function Chain(valueLinks) {
|
||||
this.nodes = [];
|
||||
this.cursor = -1;
|
||||
|
||||
if (valueLinks && valueLinks.length > 0) {
|
||||
this.push(valueLinks[0], "//");
|
||||
for (var i = 1, l = valueLinks.length; i < l; i+=2) {
|
||||
this.push(valueLinks[i+1], valueLinks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Chain.prototype.push = function(o, link) {
|
||||
if (this.nodes.length > 0 && link) this.nodes.push(new ChainNode(o, link));
|
||||
else this.nodes.push(new ChainNode(o));
|
||||
}
|
||||
|
||||
Chain.prototype.unshift = function(o, link) {
|
||||
if (this.nodes.length > 0 && link) this.nodes[0].link = link;
|
||||
this.nodes.unshift(new ChainNode(o));
|
||||
this.cursor++;
|
||||
}
|
||||
|
||||
Chain.prototype.get = function() {
|
||||
if (this.cursor < 0 || this.cursor > this.nodes.length-1) return null;
|
||||
return this.nodes[this.cursor];
|
||||
}
|
||||
|
||||
Chain.prototype.first = function() {
|
||||
this.cursor = 0;
|
||||
return this.get();
|
||||
}
|
||||
|
||||
Chain.prototype.last = function() {
|
||||
this.cursor = this.nodes.length-1;
|
||||
return this.get();
|
||||
}
|
||||
|
||||
Chain.prototype.next = function() {
|
||||
this.cursor++;
|
||||
return this.get();
|
||||
}
|
||||
|
||||
Chain.prototype.prev = function() {
|
||||
this.cursor--;
|
||||
return this.get();
|
||||
}
|
||||
|
||||
Chain.prototype.toString = function() {
|
||||
var string = "";
|
||||
for (var i = 0, l = this.nodes.length; i < l; i++) {
|
||||
if (this.nodes[i].link) string += " -("+this.nodes[i].link+")-> ";
|
||||
string += this.nodes[i].value.toString();
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
Chain.prototype.joinLeft = function() {
|
||||
var result = "";
|
||||
for (var i = 0, l = this.cursor; i < l; i++) {
|
||||
if (result && this.nodes[i].link) result += this.nodes[i].link;
|
||||
result += this.nodes[i].value.toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* USAGE:
|
||||
|
||||
var path = "one/two/three.four/five-six";
|
||||
var pathChain = new Chain(path.split(/([\/.-])/));
|
||||
print(pathChain);
|
||||
|
||||
var lineage = new Chain();
|
||||
lineage.push("Port");
|
||||
lineage.push("Les", "son");
|
||||
lineage.push("Dawn", "daughter");
|
||||
lineage.unshift("Purdie", "son");
|
||||
|
||||
print(lineage);
|
||||
|
||||
// walk left
|
||||
for (var node = lineage.last(); node !== null; node = lineage.prev()) {
|
||||
print("< "+node.value);
|
||||
}
|
||||
|
||||
// walk right
|
||||
var node = lineage.first()
|
||||
while (node !== null) {
|
||||
print(node.value);
|
||||
node = lineage.next();
|
||||
if (node && node.link) print("had a "+node.link+" named");
|
||||
}
|
||||
|
||||
*/
|
|
@ -1,144 +0,0 @@
|
|||
/**
|
||||
* @class
|
||||
<pre>
|
||||
This is a lightly modified version of Kevin Jones' JavaScript
|
||||
library Data.Dump. To download the original visit:
|
||||
<a href="http://openjsan.org/doc/k/ke/kevinj/Data/Dump/">http://openjsan.org/doc/k/ke/kevinj/Data/Dump/</a>
|
||||
|
||||
AUTHORS
|
||||
|
||||
The Data.Dump JavaScript module is written by Kevin Jones
|
||||
(kevinj@cpan.org), based on Data::Dump by Gisle Aas (gisle@aas.no),
|
||||
based on Data::Dumper by Gurusamy Sarathy (gsar@umich.edu).
|
||||
|
||||
COPYRIGHT
|
||||
|
||||
Copyright 2007 Kevin Jones. Copyright 1998-2000,2003-2004 Gisle Aas.
|
||||
Copyright 1996-1998 Gurusamy Sarathy.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the Perl Artistic License
|
||||
|
||||
See http://www.perl.com/perl/misc/Artistic.html
|
||||
</pre>
|
||||
* @static
|
||||
*/
|
||||
Dumper = {
|
||||
/** @param [...] The objects to dump. */
|
||||
dump: function () {
|
||||
if (arguments.length > 1)
|
||||
return this._dump(arguments);
|
||||
else if (arguments.length == 1)
|
||||
return this._dump(arguments[0]);
|
||||
else
|
||||
return "()";
|
||||
},
|
||||
|
||||
_dump: function (obj) {
|
||||
if (typeof obj == 'undefined') return 'undefined';
|
||||
var out;
|
||||
if (obj.serialize) { return obj.serialize(); }
|
||||
var type = this._typeof(obj);
|
||||
if (obj.circularReference) obj.circularReference++;
|
||||
switch (type) {
|
||||
case 'circular':
|
||||
out = "{ //circularReference\n}";
|
||||
break;
|
||||
case 'object':
|
||||
var pairs = new Array;
|
||||
|
||||
for (var prop in obj) {
|
||||
if (prop != "circularReference" && obj.hasOwnProperty(prop)) { //hide inherited properties
|
||||
pairs.push(prop + ': ' + this._dump(obj[prop]));
|
||||
}
|
||||
}
|
||||
|
||||
out = '{' + this._format_list(pairs) + '}';
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
for (var prop in Dumper.ESC) {
|
||||
if (Dumper.ESC.hasOwnProperty(prop)) {
|
||||
obj = obj.replace(prop, Dumper.ESC[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
// Escape UTF-8 Strings
|
||||
if (obj.match(/^[\x00-\x7f]*$/)) {
|
||||
out = '"' + obj.replace(/\"/g, "\\\"").replace(/([\n\r]+)/g, "\\$1") + '"';
|
||||
}
|
||||
else {
|
||||
out = "unescape('"+escape(obj)+"')";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'array':
|
||||
var elems = new Array;
|
||||
|
||||
for (var i=0; i<obj.length; i++) {
|
||||
elems.push( this._dump(obj[i]) );
|
||||
}
|
||||
|
||||
out = '[' + this._format_list(elems) + ']';
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
// firefox returns GMT strings from toUTCString()...
|
||||
var utc_string = obj.toUTCString().replace(/GMT/,'UTC');
|
||||
out = 'new Date("' + utc_string + '")';
|
||||
break;
|
||||
|
||||
case 'element':
|
||||
// DOM element
|
||||
out = this._dump_dom(obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
out = obj;
|
||||
}
|
||||
|
||||
out = String(out).replace(/\n/g, '\n ');
|
||||
out = out.replace(/\n (.*)$/,"\n$1");
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
_format_list: function (list) {
|
||||
if (!list.length) return '';
|
||||
var nl = list.toString().length > 60 ? '\n' : ' ';
|
||||
return nl + list.join(',' + nl) + nl;
|
||||
},
|
||||
|
||||
_typeof: function (obj) {
|
||||
if (obj && obj.circularReference && obj.circularReference > 1) return 'circular';
|
||||
if (Array.prototype.isPrototypeOf(obj)) return 'array';
|
||||
if (Date.prototype.isPrototypeOf(obj)) return 'date';
|
||||
if (typeof obj.nodeType != 'undefined') return 'element';
|
||||
return typeof(obj);
|
||||
},
|
||||
|
||||
_dump_dom: function (obj) {
|
||||
return '"' + Dumper.nodeTypes[obj.nodeType] + '"';
|
||||
}
|
||||
};
|
||||
|
||||
Dumper.ESC = {
|
||||
"\t": "\\t",
|
||||
"\n": "\\n",
|
||||
"\f": "\\f"
|
||||
};
|
||||
|
||||
Dumper.nodeTypes = {
|
||||
1: "ELEMENT_NODE",
|
||||
2: "ATTRIBUTE_NODE",
|
||||
3: "TEXT_NODE",
|
||||
4: "CDATA_SECTION_NODE",
|
||||
5: "ENTITY_REFERENCE_NODE",
|
||||
6: "ENTITY_NODE",
|
||||
7: "PROCESSING_INSTRUCTION_NODE",
|
||||
8: "COMMENT_NODE",
|
||||
9: "DOCUMENT_NODE",
|
||||
10: "DOCUMENT_TYPE_NODE",
|
||||
11: "DOCUMENT_FRAGMENT_NODE",
|
||||
12: "NOTATION_NODE"
|
||||
};
|
|
@ -1,84 +0,0 @@
|
|||
/**
|
||||
@constructor
|
||||
@example
|
||||
var _index = new Hash();
|
||||
_index.set("a", "apple");
|
||||
_index.set("b", "blue");
|
||||
_index.set("c", "coffee");
|
||||
|
||||
for (var p = _index.first(); p; p = _index.next()) {
|
||||
print(p.key+" is for "+p.value);
|
||||
}
|
||||
|
||||
*/
|
||||
var Hash = function() {
|
||||
this._map = {};
|
||||
this._keys = [];
|
||||
this._vals = [];
|
||||
this.reset();
|
||||
}
|
||||
|
||||
Hash.prototype.set = function(k, v) {
|
||||
if (k != "") {
|
||||
this._keys.push(k);
|
||||
this._map["="+k] = this._vals.length;
|
||||
this._vals.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
Hash.prototype.replace = function(k, k2, v) {
|
||||
if (k == k2) return;
|
||||
|
||||
var offset = this._map["="+k];
|
||||
this._keys[offset] = k2;
|
||||
if (typeof v != "undefined") this._vals[offset] = v;
|
||||
this._map["="+k2] = offset;
|
||||
delete(this._map["="+k]);
|
||||
}
|
||||
|
||||
Hash.prototype.drop = function(k) {
|
||||
if (k != "") {
|
||||
var offset = this._map["="+k];
|
||||
this._keys.splice(offset, 1);
|
||||
this._vals.splice(offset, 1);
|
||||
delete(this._map["="+k]);
|
||||
for (var p in this._map) {
|
||||
if (this._map[p] >= offset) this._map[p]--;
|
||||
}
|
||||
if (this._cursor >= offset && this._cursor > 0) this._cursor--;
|
||||
}
|
||||
}
|
||||
|
||||
Hash.prototype.get = function(k) {
|
||||
if (k != "") {
|
||||
return this._vals[this._map["="+k]];
|
||||
}
|
||||
}
|
||||
|
||||
Hash.prototype.keys = function() {
|
||||
return this._keys;
|
||||
}
|
||||
|
||||
Hash.prototype.hasKey = function(k) {
|
||||
if (k != "") {
|
||||
return (typeof this._map["="+k] != "undefined");
|
||||
}
|
||||
}
|
||||
|
||||
Hash.prototype.values = function() {
|
||||
return this._vals;
|
||||
}
|
||||
|
||||
Hash.prototype.reset = function() {
|
||||
this._cursor = 0;
|
||||
}
|
||||
|
||||
Hash.prototype.first = function() {
|
||||
this.reset();
|
||||
return this.next();
|
||||
}
|
||||
|
||||
Hash.prototype.next = function() {
|
||||
if (this._cursor++ < this._keys.length)
|
||||
return {key: this._keys[this._cursor-1], value: this._vals[this._cursor-1]};
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
/** Handle the creation of HTML links to documented symbols.
|
||||
@constructor
|
||||
*/
|
||||
function Link() {
|
||||
this.alias = "";
|
||||
this.src = "";
|
||||
this.file = "";
|
||||
this.text = "";
|
||||
this.innerName = "";
|
||||
this.classLink = false;
|
||||
this.targetName = "";
|
||||
|
||||
this.target = function(targetName) {
|
||||
if (defined(targetName)) this.targetName = targetName;
|
||||
return this;
|
||||
}
|
||||
this.inner = function(inner) {
|
||||
if (defined(inner)) this.innerName = inner;
|
||||
return this;
|
||||
}
|
||||
this.withText = function(text) {
|
||||
if (defined(text)) this.text = text;
|
||||
return this;
|
||||
}
|
||||
this.toSrc = function(filename) {
|
||||
if (defined(filename)) this.src = filename;
|
||||
return this;
|
||||
}
|
||||
this.toSymbol = function(alias) {
|
||||
if (defined(alias)) this.alias = new String(alias);
|
||||
return this;
|
||||
}
|
||||
this.toClass = function(alias) {
|
||||
this.classLink = true;
|
||||
return this.toSymbol(alias);
|
||||
}
|
||||
this.toFile = function(file) {
|
||||
if (defined(file)) this.file = file;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.toString = function() {
|
||||
var linkString;
|
||||
var thisLink = this;
|
||||
|
||||
if (this.alias) {
|
||||
linkString = this.alias.replace(/(^|[^a-z$0-9_#.:^-])([|a-z$0-9_#.:^-]+)($|[^a-z$0-9_#.:^-])/i,
|
||||
function(match, prematch, symbolName, postmatch) {
|
||||
var symbolNames = symbolName.split("|");
|
||||
var links = [];
|
||||
for (var i = 0, l = symbolNames.length; i < l; i++) {
|
||||
thisLink.alias = symbolNames[i];
|
||||
links.push(thisLink._makeSymbolLink(symbolNames[i]));
|
||||
}
|
||||
return prematch+links.join("|")+postmatch;
|
||||
}
|
||||
);
|
||||
}
|
||||
else if (this.src) {
|
||||
linkString = thisLink._makeSrcLink(this.src);
|
||||
}
|
||||
else if (this.file) {
|
||||
linkString = thisLink._makeFileLink(this.file);
|
||||
}
|
||||
|
||||
return linkString;
|
||||
}
|
||||
}
|
||||
|
||||
/** prefixed for hashes */
|
||||
Link.hashPrefix = "";
|
||||
|
||||
/** Appended to the front of relative link paths. */
|
||||
Link.base = "";
|
||||
|
||||
Link.symbolNameToLinkName = function(symbol) {
|
||||
var linker = "";
|
||||
if (symbol.isStatic) linker = ".";
|
||||
else if (symbol.isInner) linker = "-";
|
||||
|
||||
return Link.hashPrefix+linker+symbol.name;
|
||||
}
|
||||
|
||||
Link.getSymbol= function(alias) {
|
||||
var symbol= Link.symbolSet.getSymbol(alias);
|
||||
|
||||
if (symbol)
|
||||
return symbol;
|
||||
|
||||
if ('#'!==alias.charAt(0) || !Link.currentSymbol)
|
||||
return null;
|
||||
|
||||
// resolve relative name
|
||||
var container= Link.currentSymbol;
|
||||
|
||||
while (container)
|
||||
{
|
||||
symbol= Link.symbolSet.getSymbol(container.alias + alias);
|
||||
if (symbol)
|
||||
return symbol;
|
||||
|
||||
// No superclass
|
||||
if (!container.augments.length)
|
||||
return null;
|
||||
|
||||
container= Link.symbolSet.getSymbol(container.augments[0].desc);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Create a link to another symbol. */
|
||||
Link.prototype._makeSymbolLink = function(alias) {
|
||||
var linkBase = Link.base+publish.conf.symbolsDir;
|
||||
var linkTo = Link.getSymbol(alias);
|
||||
var linkPath;
|
||||
var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
|
||||
|
||||
// if there is no symbol by that name just return the name unaltered
|
||||
if (!linkTo)
|
||||
return this.text || alias;
|
||||
|
||||
// it's a symbol in another file
|
||||
else {
|
||||
if (!linkTo.is("CONSTRUCTOR") && !linkTo.isNamespace) { // it's a method or property
|
||||
linkPath= (Link.filemap) ? Link.filemap[linkTo.memberOf] :
|
||||
escape(linkTo.memberOf) || "_global_";
|
||||
if (linkTo.isEvent)
|
||||
linkPath += publish.conf.ext + "#event:" + Link.symbolNameToLinkName(linkTo);
|
||||
else
|
||||
linkPath += publish.conf.ext + "#" + Link.symbolNameToLinkName(linkTo);
|
||||
}
|
||||
else {
|
||||
linkPath = (Link.filemap)? Link.filemap[linkTo.alias] : escape(linkTo.alias);
|
||||
linkPath += publish.conf.ext;// + (this.classLink? "":"#" + Link.hashPrefix + "constructor");
|
||||
}
|
||||
linkPath = linkBase + linkPath
|
||||
}
|
||||
|
||||
var linkText= this.text || alias;
|
||||
|
||||
var link = {linkPath: linkPath, linkText: linkText, linkInner: (this.innerName? "#"+this.innerName : "")};
|
||||
|
||||
if (typeof JSDOC.PluginManager != "undefined") {
|
||||
JSDOC.PluginManager.run("onSymbolLink", link);
|
||||
}
|
||||
|
||||
return "<a href=\""+link.linkPath+link.linkInner+"\""+target+">"+link.linkText+"</a>";
|
||||
}
|
||||
|
||||
/** Create a link to a source file. */
|
||||
Link.prototype._makeSrcLink = function(srcFilePath) {
|
||||
var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
|
||||
|
||||
// transform filepath into a filename
|
||||
var srcFile = srcFilePath.replace(/\.\.?[\\\/]/g, "").replace(/[:\\\/]/g, "_");
|
||||
var outFilePath = Link.base + publish.conf.srcDir + srcFile + publish.conf.ext;
|
||||
|
||||
if (!this.text) this.text = FilePath.fileName(srcFilePath);
|
||||
return "<a href=\""+outFilePath+"\""+target+">"+this.text+"</a>";
|
||||
}
|
||||
|
||||
/** Create a link to a source file. */
|
||||
Link.prototype._makeFileLink = function(filePath) {
|
||||
var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
|
||||
|
||||
var outFilePath = Link.base + filePath;
|
||||
|
||||
if (!this.text) this.text = filePath;
|
||||
return "<a href=\""+outFilePath+"\""+target+">"+this.text+"</a>";
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
_global_ = this;
|
||||
|
||||
function Namespace(name, f) {
|
||||
var n = name.split(".");
|
||||
for (var o = _global_, i = 0, l = n.length; i < l; i++) {
|
||||
o = o[n[i]] = o[n[i]] || {};
|
||||
}
|
||||
|
||||
if (f) f();
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/** @namespace */
|
||||
Opt = {
|
||||
/**
|
||||
* Get commandline option values.
|
||||
* @param {Array} args Commandline arguments. Like ["-a=xml", "-b", "--class=new", "--debug"]
|
||||
* @param {object} optNames Map short names to long names. Like {a:"accept", b:"backtrace", c:"class", d:"debug"}.
|
||||
* @return {object} Short names and values. Like {a:"xml", b:true, c:"new", d:true}
|
||||
*/
|
||||
get: function(args, optNames) {
|
||||
var opt = {"_": []}; // the unnamed option allows multiple values
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = new String(args[i]);
|
||||
var name;
|
||||
var value;
|
||||
if (arg.charAt(0) == "-") {
|
||||
if (arg.charAt(1) == "-") { // it's a longname like --foo
|
||||
arg = arg.substring(2);
|
||||
var m = arg.split("=");
|
||||
name = m.shift();
|
||||
value = m.shift();
|
||||
if (typeof value == "undefined") value = true;
|
||||
|
||||
for (var n in optNames) { // convert it to a shortname
|
||||
if (name == optNames[n]) {
|
||||
name = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // it's a shortname like -f
|
||||
arg = arg.substring(1);
|
||||
var m = arg.split("=");
|
||||
name = m.shift();
|
||||
value = m.shift();
|
||||
if (typeof value == "undefined") value = true;
|
||||
|
||||
for (var n in optNames) { // find the matching key
|
||||
if (name == n || name+'[]' == n) {
|
||||
name = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name.match(/(.+)\[\]$/)) { // it's an array type like n[]
|
||||
name = RegExp.$1;
|
||||
if (!opt[name]) opt[name] = [];
|
||||
}
|
||||
|
||||
if (opt[name] && opt[name].push) {
|
||||
opt[name].push(value);
|
||||
}
|
||||
else {
|
||||
opt[name] = value;
|
||||
}
|
||||
}
|
||||
else { // not associated with any optname
|
||||
opt._.push(args[i]);
|
||||
}
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(11, "Testing Opt.");
|
||||
|
||||
is(
|
||||
typeof Opt,
|
||||
"object",
|
||||
"Opt is an object."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof Opt.get,
|
||||
"function",
|
||||
"Opt.get is a function."
|
||||
);
|
||||
|
||||
var optNames = {a:"accept", b:"backtrace", c:"class", d:"debug", "e[]":"exceptions"};
|
||||
var t_options = Opt.get(["-a=xml", "-b", "--class=new", "--debug", "-e=one", "-e=two", "foo", "bar"], optNames);
|
||||
|
||||
is(
|
||||
t_options.a,
|
||||
"xml",
|
||||
"an option defined with a short name can be accessed by its short name."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.b,
|
||||
true,
|
||||
"an option defined with a short name and no value are true."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.c,
|
||||
"new",
|
||||
"an option defined with a long name can be accessed by its short name."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.d,
|
||||
true,
|
||||
"an option defined with a long name and no value are true."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof t_options.e,
|
||||
"object",
|
||||
"an option that can accept multiple values is defined."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.e.length,
|
||||
2,
|
||||
"an option that can accept multiple values can have more than one value."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.e[1],
|
||||
"two",
|
||||
"an option that can accept multiple values can be accessed as an array."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof t_options._,
|
||||
"object",
|
||||
"the property '_' is defined for unnamed options."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options._[0],
|
||||
"foo",
|
||||
"the property '_' can be accessed as an array."
|
||||
);
|
||||
*/
|
|
@ -1,26 +0,0 @@
|
|||
/**@constructor*/
|
||||
function Reflection(obj) {
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
Reflection.prototype.getConstructorName = function() {
|
||||
if (this.obj.constructor.name) return this.obj.constructor.name;
|
||||
var src = this.obj.constructor.toSource();
|
||||
var name = src.substring(name.indexOf("function")+8, src.indexOf('(')).replace(/ /g,'');
|
||||
return name;
|
||||
}
|
||||
|
||||
Reflection.prototype.getMethod = function(name) {
|
||||
for (var p in this.obj) {
|
||||
if (p == name && typeof(this.obj[p]) == "function") return this.obj[p];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reflection.prototype.getParameterNames = function() {
|
||||
var src = this.obj.toSource();
|
||||
src = src.substring(
|
||||
src.indexOf("(", 8)+1, src.indexOf(")")
|
||||
);
|
||||
return src.split(/, ?/);
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/**
|
||||
@name String
|
||||
@class Additions to the core string object.
|
||||
*/
|
||||
|
||||
/** @author Steven Levithan, released as public domain. */
|
||||
String.prototype.trim = function() {
|
||||
var str = this.replace(/^\s+/, '');
|
||||
for (var i = str.length - 1; i >= 0; i--) {
|
||||
if (/\S/.test(str.charAt(i))) {
|
||||
str = str.substring(0, i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
/*t:
|
||||
plan(6, "Testing String.prototype.trim.");
|
||||
|
||||
var s = " a bc ".trim();
|
||||
is(s, "a bc", "multiple spaces front and back are trimmed.");
|
||||
|
||||
s = "a bc\n\n".trim();
|
||||
is(s, "a bc", "newlines only in back are trimmed.");
|
||||
|
||||
s = "\ta bc".trim();
|
||||
is(s, "a bc", "tabs only in front are trimmed.");
|
||||
|
||||
s = "\n \t".trim();
|
||||
is(s, "", "an all-space string is trimmed to empty.");
|
||||
|
||||
s = "a b\nc".trim();
|
||||
is(s, "a b\nc", "a string with no spaces in front or back is trimmed to itself.");
|
||||
|
||||
s = "".trim();
|
||||
is(s, "", "an empty string is trimmed to empty.");
|
||||
|
||||
*/
|
||||
|
||||
String.prototype.balance = function(open, close) {
|
||||
var i = 0;
|
||||
while (this.charAt(i) != open) {
|
||||
if (i == this.length) return [-1, -1];
|
||||
i++;
|
||||
}
|
||||
|
||||
var j = i+1;
|
||||
var balance = 1;
|
||||
while (j < this.length) {
|
||||
if (this.charAt(j) == open) balance++;
|
||||
if (this.charAt(j) == close) balance--;
|
||||
if (balance == 0) break;
|
||||
j++;
|
||||
if (j == this.length) return [-1, -1];
|
||||
}
|
||||
|
||||
return [i, j];
|
||||
}
|
||||
/*t:
|
||||
plan(16, "Testing String.prototype.balance.");
|
||||
|
||||
var s = "{abc}".balance("{","}");
|
||||
is(s[0], 0, "opener in first is found.");
|
||||
is(s[1], 4, "closer in last is found.");
|
||||
|
||||
s = "ab{c}de".balance("{","}");
|
||||
is(s[0], 2, "opener in middle is found.");
|
||||
is(s[1], 4, "closer in middle is found.");
|
||||
|
||||
s = "a{b{c}de}f".balance("{","}");
|
||||
is(s[0], 1, "nested opener is found.");
|
||||
is(s[1], 8, "nested closer is found.");
|
||||
|
||||
s = "{}".balance("{","}");
|
||||
is(s[0], 0, "opener with no content is found.");
|
||||
is(s[1], 1, "closer with no content is found.");
|
||||
|
||||
s = "".balance("{","}");
|
||||
is(s[0], -1, "empty string opener is -1.");
|
||||
is(s[1], -1, "empty string closer is -1.");
|
||||
|
||||
s = "{abc".balance("{","}");
|
||||
is(s[0], -1, "opener with no closer returns -1.");
|
||||
is(s[1], -1, "no closer returns -1.");
|
||||
|
||||
s = "abc".balance("{","}");
|
||||
is(s[0], -1, "no opener or closer returns -1 for opener.");
|
||||
is(s[1], -1, "no opener or closer returns -1 for closer.");
|
||||
|
||||
s = "a<bc}de".balance("<","}");
|
||||
is(s[0], 1, "unmatching opener is found.");
|
||||
is(s[1], 4, "unmatching closer is found.");
|
||||
*/
|
|
@ -1,129 +0,0 @@
|
|||
/**
|
||||
* @fileOverview
|
||||
* @name JsTestrun
|
||||
* @author Michael Mathews micmath@gmail.com
|
||||
* @url $HeadURL: http://jsdoc-toolkit.googlecode.com/svn/trunk/jsdoc-toolkit/app/frame/Testrun.js $
|
||||
* @revision $Id: Testrun.js 418 2008-01-15 21:40:33Z micmath $
|
||||
* @license <a href="http://en.wikipedia.org/wiki/MIT_License">X11/MIT License</a>
|
||||
* (See the accompanying README file for full details.)
|
||||
*/
|
||||
|
||||
/**
|
||||
Yet another unit testing tool for JavaScript.
|
||||
@author Michael Mathews <a href="mailto:micmath@gmail.com">micmath@gmail.com</a>
|
||||
@param {object} testCases Properties are testcase names, values are functions to execute as tests.
|
||||
*/
|
||||
function testrun(testCases) {
|
||||
var ran = 0;
|
||||
for (t in testCases) {
|
||||
var result = testCases[t]();
|
||||
ran++;
|
||||
}
|
||||
|
||||
return testrun.reportOut+"-------------------------------\n"+((testrun.fails>0)? ":( Failed "+testrun.fails+"/" : ":) Passed all ")+testrun.count+" test"+((testrun.count == 1)? "":"s")+".\n";
|
||||
}
|
||||
|
||||
|
||||
testrun.count = 0;
|
||||
testrun.current = null;
|
||||
testrun.passes = 0;
|
||||
testrun.fails = 0;
|
||||
testrun.reportOut = "";
|
||||
|
||||
/** @private */
|
||||
testrun.report = function(text) {
|
||||
testrun.reportOut += text+"\n";
|
||||
}
|
||||
|
||||
/**
|
||||
Check if test evaluates to true.
|
||||
@param {string} test To be evaluated.
|
||||
@param {string} message Optional. To be displayed in the report.
|
||||
@return {boolean} True if the string test evaluates to true.
|
||||
*/
|
||||
ok = function(test, message) {
|
||||
testrun.count++;
|
||||
|
||||
var result;
|
||||
try {
|
||||
result = eval(test);
|
||||
|
||||
if (result) {
|
||||
testrun.passes++;
|
||||
testrun.report(" OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
else {
|
||||
testrun.fails++;
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Check if test is same as expected.
|
||||
@param {string} test To be evaluated.
|
||||
@param {string} expected
|
||||
@param {string} message Optional. To be displayed in the report.
|
||||
@return {boolean} True if (test == expected). Note that the comparison is not a strict equality check.
|
||||
*/
|
||||
is = function(test, expected, message) {
|
||||
testrun.count++;
|
||||
|
||||
var result;
|
||||
try {
|
||||
result = eval(test);
|
||||
|
||||
if (result == expected) {
|
||||
testrun.passes++
|
||||
testrun.report(" OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
else {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
testrun.report("expected: "+expected);
|
||||
testrun.report(" got: "+result);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
testrun.report("expected: "+expected);
|
||||
testrun.report(" got: "+result);}
|
||||
}
|
||||
|
||||
/**
|
||||
Check if test matches pattern.
|
||||
@param {string} test To be evaluated.
|
||||
@param {string} pattern Used to create a RegExp.
|
||||
@param {string} message Optional. To be displayed in the report.
|
||||
@return {boolean} True if test matches pattern.
|
||||
*/
|
||||
like = function(test, pattern, message) {
|
||||
testrun.count++;
|
||||
|
||||
var result;
|
||||
try {
|
||||
result = eval(test);
|
||||
var rgx = new RegExp(pattern);
|
||||
|
||||
if (rgx.test(result)) {
|
||||
testrun.passes++
|
||||
testrun.report(" OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
else {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
testrun.report(" this: "+result);
|
||||
testrun.report("is not like: "+pattern);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
This is the main container for the FOODOC handler.
|
||||
@namespace
|
||||
*/
|
||||
FOODOC = {
|
||||
};
|
||||
|
||||
/** The current version string of this application. */
|
||||
FOODOC.VERSION = "1.0";
|
||||
|
||||
FOODOC.handle = function(srcFile, src) {
|
||||
LOG.inform("Handling file '" + srcFile + "'");
|
||||
|
||||
return [
|
||||
new JSDOC.Symbol(
|
||||
"foo",
|
||||
[],
|
||||
"VIRTUAL",
|
||||
new JSDOC.DocComment("/** This is a foo. */")
|
||||
)
|
||||
];
|
||||
};
|
||||
|
||||
FOODOC.publish = function(symbolgroup) {
|
||||
LOG.inform("Publishing symbolgroup.");
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* This is the main container for the XMLDOC handler.
|
||||
* @namespace
|
||||
* @author Brett Fattori (bfattori@fry.com)
|
||||
* @version $Revision: 498 $
|
||||
*/
|
||||
XMLDOC = {
|
||||
|
||||
};
|
||||
|
||||
/** The current version string of this application. */
|
||||
XMLDOC.VERSION = "1.0";
|
||||
|
||||
/** Include the library necessary to handle XML files */
|
||||
IO.includeDir("handlers/XMLDOC/");
|
||||
|
||||
/**
|
||||
* @type Symbol[]
|
||||
*/
|
||||
XMLDOC.handle = function(srcFile, src) {
|
||||
|
||||
};
|
||||
|
||||
XMLDOC.publish = function(symbolgroup) {
|
||||
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
LOG.inform("XMLDOC.DomReader loaded");
|
||||
|
||||
XMLDOC.DomReader = function(root) {
|
||||
|
||||
this.dom = root;
|
||||
|
||||
/**
|
||||
* The current node the reader is on
|
||||
*/
|
||||
this.node = root;
|
||||
|
||||
/**
|
||||
* Get the current node the reader is on
|
||||
* @type XMLDOC.Parser.node
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.getNode = function() {
|
||||
return this.node;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the node the reader should be positioned on.
|
||||
* @param node {XMLDOC.Parser.node}
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.setNode = function(node) {
|
||||
this.node = node;
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper method to make sure the current node will
|
||||
* never return null, unless null is passed as the root.
|
||||
* @param step {String} An expression to evaluate - should return a node or null
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.navigate = function(step) {
|
||||
var n;
|
||||
if ((n = step) != null)
|
||||
{
|
||||
this.node = n;
|
||||
return this.node;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the root node of the current node's document.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.root = function() {
|
||||
this.navigate(this.dom);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the parent of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.parent = function() {
|
||||
return this.navigate(this.node.parentNode());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the first child of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.firstChild = function() {
|
||||
return this.navigate(this.node.firstChild());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the last child of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.lastChild = function() {
|
||||
return this.navigate(this.node.lastChild());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the next sibling of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.nextSibling = function() {
|
||||
return this.navigate(this.node.nextSibling());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the previous sibling of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.prevSibling = function() {
|
||||
return this.navigate(this.node.prevSibling());
|
||||
};
|
||||
|
||||
//===============================================================================================
|
||||
// Support methods
|
||||
|
||||
/**
|
||||
* Walk the tree starting with the current node, calling the plug-in for
|
||||
* each node visited. Each time the plug-in is called, the DomReader
|
||||
* is passed as the only parameter. Use the {@link XMLDOC.DomReader#getNode} method
|
||||
* to access the current node. <i>This method uses a depth first traversal pattern.</i>
|
||||
*
|
||||
* @param srcFile {String} The source file being evaluated
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.getSymbols = function(srcFile)
|
||||
{
|
||||
XMLDOC.DomReader.symbols = [];
|
||||
XMLDOC.DomReader.currentFile = srcFile;
|
||||
JSDOC.Symbol.srcFile = (srcFile || "");
|
||||
|
||||
if (defined(JSDOC.PluginManager)) {
|
||||
JSDOC.PluginManager.run("onDomGetSymbols", this);
|
||||
}
|
||||
|
||||
return XMLDOC.DomReader.symbols;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the node with the given name using a depth first traversal.
|
||||
* Does not modify the DomReader's current node.
|
||||
*
|
||||
* @param name {String} The name of the node to find
|
||||
* @return the node that was found, or null if not found
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.findNode = function(name)
|
||||
{
|
||||
var findNode = null;
|
||||
|
||||
// Start at the current node and move into the subtree,
|
||||
// looking for the node with the given name
|
||||
function deeper(node, find)
|
||||
{
|
||||
var look = null;
|
||||
|
||||
if (node) {
|
||||
if (node.name == find)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
if (node.firstChild())
|
||||
{
|
||||
look = deeper(node.firstChild(), find);
|
||||
}
|
||||
|
||||
if (!look && node.nextSibling())
|
||||
{
|
||||
look = deeper(node.nextSibling(), find);
|
||||
}
|
||||
}
|
||||
|
||||
return look;
|
||||
}
|
||||
|
||||
return deeper(this.getNode().firstChild(), name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the next node with the given name using a depth first traversal.
|
||||
*
|
||||
* @param name {String} The name of the node to find
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.findPreviousNode = function(name)
|
||||
{
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
LOG.inform("XMLDOC.symbolize loaded");
|
||||
|
||||
/**
|
||||
* Convert the source file to a set of symbols
|
||||
*/
|
||||
XMLDOC.symbolize = function(srcFile, src) {
|
||||
|
||||
LOG.inform("Symbolizing file '" + srcFile + "'");
|
||||
|
||||
// XML files already have a defined structure, so we don't need to
|
||||
// do anything but parse them. The DOM reader can create a symbol
|
||||
// table from the parsed XML.
|
||||
var dr = new XMLDOC.DomReader(XMLDOC.Parser.parse(src));
|
||||
return dr.getSymbols(srcFile);
|
||||
|
||||
};
|
|
@ -1,292 +0,0 @@
|
|||
LOG.inform("XMLDOC.Parser loaded");
|
||||
|
||||
/**
|
||||
* XML Parser object. Returns an {@link #XMLDOC.Parser.node} which is
|
||||
* the root element of the parsed document.
|
||||
* <p/>
|
||||
* By default, this parser will only handle well formed XML. To
|
||||
* allow the parser to handle HTML, set the <tt>XMLDOC.Parser.strictMode</tt>
|
||||
* variable to <tt>false</tt> before calling <tt>XMLDOC.Parser.parse()</tt>.
|
||||
* <p/>
|
||||
* <i>Note: If you pass poorly formed XML, it will cause the parser to throw
|
||||
* an exception.</i>
|
||||
*
|
||||
* @author Brett Fattori (bfattori@fry.com)
|
||||
* @author $Author: micmath $
|
||||
* @version $Revision: 497 $
|
||||
*/
|
||||
XMLDOC.Parser = {};
|
||||
|
||||
/**
|
||||
* Strict mode setting. Setting this to false allows HTML-style source to
|
||||
* be parsed. Normally, well formed XML has defined end tags, or empty tags
|
||||
* are properly formed. Default: <tt>true</tt>
|
||||
* @type Boolean
|
||||
*/
|
||||
XMLDOC.Parser.strictMode = true;
|
||||
|
||||
/**
|
||||
* A node in an XML Document. Node types are ROOT, ELEMENT, COMMENT, PI, and TEXT.
|
||||
* @param parent {XMLDOC.Parser.node} The parent node
|
||||
* @param name {String} The node name
|
||||
* @param type {String} One of the types
|
||||
*/
|
||||
XMLDOC.Parser.node = function(parent, name, type)
|
||||
{
|
||||
this.name = name;
|
||||
this.type = type || "ELEMENT";
|
||||
this.parent = parent;
|
||||
this.charData = "";
|
||||
this.attrs = {};
|
||||
this.nodes = [];
|
||||
this.cPtr = 0;
|
||||
|
||||
XMLDOC.Parser.node.prototype.getAttributeNames = function() {
|
||||
var a = [];
|
||||
for (var o in this.attrs)
|
||||
{
|
||||
a.push(o);
|
||||
}
|
||||
|
||||
return a;
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.getAttribute = function(attr) {
|
||||
return this.attrs[attr];
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.setAttribute = function(attr, val) {
|
||||
this.attrs[attr] = val;
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.getChild = function(idx) {
|
||||
return this.nodes[idx];
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.parentNode = function() {
|
||||
return this.parent;
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.firstChild = function() {
|
||||
return this.nodes[0];
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.lastChild = function() {
|
||||
return this.nodes[this.nodes.length - 1];
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.nextSibling = function() {
|
||||
var p = this.parent;
|
||||
if (p && (p.nodes.indexOf(this) + 1 != p.nodes.length))
|
||||
{
|
||||
return p.getChild(p.nodes.indexOf(this) + 1);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.prevSibling = function() {
|
||||
var p = this.parent;
|
||||
if (p && (p.nodes.indexOf(this) - 1 >= 0))
|
||||
{
|
||||
return p.getChild(p.nodes.indexOf(this) - 1);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse an XML Document from the specified source. The XML should be
|
||||
* well formed, unless strict mode is disabled, then the parser will
|
||||
* handle HTML-style XML documents.
|
||||
* @param src {String} The source to parse
|
||||
*/
|
||||
XMLDOC.Parser.parse = function(src)
|
||||
{
|
||||
var A = [];
|
||||
|
||||
// Normailize whitespace
|
||||
A = src.split("\r\n");
|
||||
src = A.join("\n");
|
||||
A = src.split("\r");
|
||||
src = A.join("\n");
|
||||
|
||||
// Remove XML and DOCTYPE specifier
|
||||
src.replace(/<\?XML .*\?>/i, "");
|
||||
src.replace(/<!DOCTYPE .*\>/i, "");
|
||||
|
||||
// The document is the root node and cannot be modified or removed
|
||||
var doc = new XMLDOC.Parser.node(null, "ROOT", "DOCUMENT");
|
||||
|
||||
// Let's break it down
|
||||
XMLDOC.Parser.eat(doc, src);
|
||||
|
||||
return doc;
|
||||
};
|
||||
|
||||
/**
|
||||
* The XML fragment processing routine. This method is private and should not be called
|
||||
* directly.
|
||||
* @param parentNode {XMLDOC.Parser.node} The node which is the parent of this fragment
|
||||
* @param src {String} The source within the fragment to process
|
||||
* @private
|
||||
*/
|
||||
XMLDOC.Parser.eat = function(parentNode, src)
|
||||
{
|
||||
// A simple tag def
|
||||
var reTag = new RegExp("<(!|)(\\?|--|)((.|\\s)*?)\\2>","g");
|
||||
|
||||
// Special tag types
|
||||
var reCommentTag = /<!--((.|\s)*?)-->/;
|
||||
var rePITag = /<\?((.|\s)*?)\?>/;
|
||||
|
||||
// A start tag (with potential empty marker)
|
||||
var reStartTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*(\/)?>/;
|
||||
|
||||
// An empty HTML style tag (not proper XML, but we'll accept it so we can process HTML)
|
||||
var reHTMLEmptyTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*>/;
|
||||
|
||||
// Fully enclosing tag with nested tags
|
||||
var reEnclosingTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*?)\4)*>((.|\s)*?)<\/\1>/;
|
||||
|
||||
// Breaks down attributes
|
||||
var reAttributes = new RegExp(" +([\\w_\\-]*)=(\"|')(.*?)\\2","g");
|
||||
|
||||
// Find us a tag
|
||||
var tag;
|
||||
while ((tag = reTag.exec(src)) != null)
|
||||
{
|
||||
if (tag.index > 0)
|
||||
{
|
||||
// The next tag has some text before it
|
||||
var text = src.substring(0, tag.index).replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1");
|
||||
|
||||
if (text.length > 0 && (text != "\n"))
|
||||
{
|
||||
var txtnode = new XMLDOC.Parser.node(parentNode, "", "TEXT");
|
||||
txtnode.charData = text;
|
||||
|
||||
// Append the new text node
|
||||
parentNode.nodes.push(txtnode);
|
||||
}
|
||||
|
||||
// Reset the lastIndex of reTag
|
||||
reTag.lastIndex -= src.substring(0, tag.index).length;
|
||||
|
||||
// Eat the text
|
||||
src = src.substring(tag.index);
|
||||
}
|
||||
|
||||
if (reCommentTag.test(tag[0]))
|
||||
{
|
||||
// Is this a comment?
|
||||
var comment = new XMLDOC.Parser.node(parentNode, "", "COMMENT");
|
||||
comment.charData = reCommentTag.exec(tag[0])[1];
|
||||
|
||||
// Append the comment
|
||||
parentNode.nodes.push(comment);
|
||||
|
||||
// Move the lastIndex of reTag
|
||||
reTag.lastIndex -= tag[0].length;
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(reCommentTag, "");
|
||||
}
|
||||
else if (rePITag.test(tag[0]))
|
||||
{
|
||||
// Is this a processing instruction?
|
||||
var pi = new XMLDOC.Parser.node(parentNode, "", "PI");
|
||||
pi.charData = rePITag.exec(tag[0])[1];
|
||||
|
||||
// Append the processing instruction
|
||||
parentNode.nodes.push(pi);
|
||||
|
||||
// Move the lastIndex of reTag
|
||||
reTag.lastIndex -= tag[0].length;
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(rePITag, "");
|
||||
}
|
||||
else if (reStartTag.test(tag[0]))
|
||||
{
|
||||
// Break it down
|
||||
var e = reStartTag.exec(tag[0]);
|
||||
var elem = new XMLDOC.Parser.node(parentNode, e[1], "ELEMENT");
|
||||
|
||||
// Get attributes from the tag
|
||||
var a;
|
||||
while ((a = reAttributes.exec(e[2])) != null )
|
||||
{
|
||||
elem.attrs[a[1]] = a[3];
|
||||
}
|
||||
|
||||
// Is this an empty XML-style tag?
|
||||
if (e[6] == "/")
|
||||
{
|
||||
// Append the empty element
|
||||
parentNode.nodes.push(elem);
|
||||
|
||||
// Move the lastIndex of reTag (include the start tag length)
|
||||
reTag.lastIndex -= e[0].length;
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(reStartTag, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for malformed XML tags
|
||||
var htmlParsed = false;
|
||||
var htmlStartTag = reHTMLEmptyTag.exec(src);
|
||||
|
||||
// See if there isn't an end tag within this block
|
||||
var reHTMLEndTag = new RegExp("</" + htmlStartTag[1] + ">");
|
||||
var htmlEndTag = reHTMLEndTag.exec(src);
|
||||
|
||||
if (XMLDOC.Parser.strictMode && htmlEndTag == null)
|
||||
{
|
||||
// Poorly formed XML fails in strict mode
|
||||
var err = new Error("Malformed XML passed to XMLDOC.Parser... Error contains malformed 'src'");
|
||||
err.src = src;
|
||||
throw err;
|
||||
}
|
||||
else if (htmlEndTag == null)
|
||||
{
|
||||
// This is an HTML-style empty tag, store the element for it in non-strict mode
|
||||
parentNode.nodes.push(elem);
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(reHTMLEmptyTag, "");
|
||||
htmlParsed = true;
|
||||
}
|
||||
|
||||
// If we didn't parse HTML-style, it must be an enclosing tag
|
||||
if (!htmlParsed)
|
||||
{
|
||||
var enc = reEnclosingTag.exec(src);
|
||||
|
||||
// Go deeper into the document
|
||||
XMLDOC.Parser.eat(elem, enc[6]);
|
||||
|
||||
// Append the new element node
|
||||
parentNode.nodes.push(elem);
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(reEnclosingTag, "");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the lastIndex of reTag
|
||||
reTag.lastIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// No tag was found... append the text if there is any
|
||||
src = src.replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1");
|
||||
if (src.length > 0 && (src != "\n"))
|
||||
{
|
||||
var txtNode = new XMLDOC.Parser.node(parentNode, "", "TEXT");
|
||||
txtNode.charData = src;
|
||||
|
||||
// Append the new text node
|
||||
parentNode.nodes.push(txtNode);
|
||||
}
|
||||
};
|
|
@ -1,104 +0,0 @@
|
|||
/**
|
||||
@overview
|
||||
@date $Date: 2009-10-28 23:25:32 +0000 (Wed, 28 Oct 2009) $
|
||||
@version $Revision: 816 $
|
||||
@location $HeadURL: http://jsdoc-toolkit.googlecode.com/svn/trunk/jsdoc-toolkit/app/lib/JSDOC.js $
|
||||
@name JSDOC.js
|
||||
*/
|
||||
|
||||
/**
|
||||
This is the main container for the JSDOC application.
|
||||
@namespace
|
||||
*/
|
||||
JSDOC = {
|
||||
};
|
||||
|
||||
/**
|
||||
@requires Opt
|
||||
*/
|
||||
if (typeof arguments == "undefined") arguments = [];
|
||||
JSDOC.opt = Opt.get(
|
||||
arguments,
|
||||
{
|
||||
a: "allfunctions",
|
||||
c: "conf",
|
||||
d: "directory",
|
||||
"D[]": "define",
|
||||
e: "encoding",
|
||||
"E[]": "exclude",
|
||||
h: "help",
|
||||
n: "nocode",
|
||||
o: "out",
|
||||
p: "private",
|
||||
q: "quiet",
|
||||
r: "recurse",
|
||||
S: "securemodules",
|
||||
s: "suppress",
|
||||
t: "template",
|
||||
T: "testmode",
|
||||
u: "unique",
|
||||
v: "verbose",
|
||||
x: "ext"
|
||||
}
|
||||
);
|
||||
|
||||
/** The current version string of this application. */
|
||||
JSDOC.VERSION = "2.3.3-beta";
|
||||
|
||||
/** Print out usage information and quit. */
|
||||
JSDOC.usage = function() {
|
||||
print("USAGE: java -jar jsrun.jar app/run.js [OPTIONS] <SRC_DIR> <SRC_FILE> ...");
|
||||
print("");
|
||||
print("OPTIONS:");
|
||||
print(" -a or --allfunctions\n Include all functions, even undocumented ones.\n");
|
||||
print(" -c or --conf\n Load a configuration file.\n");
|
||||
print(" -d=<PATH> or --directory=<PATH>\n Output to this directory (defaults to \"out\").\n");
|
||||
print(" -D=\"myVar:My value\" or --define=\"myVar:My value\"\n Multiple. Define a variable, available in JsDoc as JSDOC.opt.D.myVar.\n");
|
||||
print(" -e=<ENCODING> or --encoding=<ENCODING>\n Use this encoding to read and write files.\n");
|
||||
print(" -E=\"REGEX\" or --exclude=\"REGEX\"\n Multiple. Exclude files based on the supplied regex.\n");
|
||||
print(" -h or --help\n Show this message and exit.\n");
|
||||
print(" -n or --nocode\n Ignore all code, only document comments with @name tags.\n");
|
||||
print(" -o=<PATH> or --out=<PATH>\n Print log messages to a file (defaults to stdout).\n");
|
||||
print(" -p or --private\n Include symbols tagged as private, underscored and inner symbols.\n");
|
||||
print(" -q or --quiet\n Do not output any messages, not even warnings.\n");
|
||||
print(" -r=<DEPTH> or --recurse=<DEPTH>\n Descend into src directories.\n");
|
||||
print(" -s or --suppress\n Suppress source code output.\n");
|
||||
print(" -S or --securemodules\n Use Secure Modules mode to parse source code.\n");
|
||||
print(" -t=<PATH> or --template=<PATH>\n Required. Use this template to format the output.\n");
|
||||
print(" -T or --test\n Run all unit tests and exit.\n");
|
||||
print(" -u or --unique\n Force file names to be unique, but not based on symbol names.\n");
|
||||
print(" -v or --verbose\n Provide verbose feedback about what is happening.\n");
|
||||
print(" -x=<EXT>[,EXT]... or --ext=<EXT>[,EXT]...\n Scan source files with the given extension/s (defaults to js).\n");
|
||||
|
||||
quit();
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(4, "Testing JSDOC namespace.");
|
||||
|
||||
is(
|
||||
typeof JSDOC,
|
||||
"object",
|
||||
"JSDOC.usage is a function."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof JSDOC.VERSION,
|
||||
"string",
|
||||
"JSDOC.VERSION is a string."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof JSDOC.usage,
|
||||
"function",
|
||||
"JSDOC.usage is a function."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof JSDOC.opt,
|
||||
"object",
|
||||
"JSDOC.opt is a object."
|
||||
);
|
||||
*/
|
||||
|
||||
if (this.IO) IO.includeDir("lib/JSDOC/");
|
|
@ -1,204 +0,0 @@
|
|||
if (typeof JSDOC == "undefined") JSDOC = {};
|
||||
|
||||
/**
|
||||
Create a new DocComment. This takes a raw documentation comment,
|
||||
and wraps it in useful accessors.
|
||||
@class Represents a documentation comment object.
|
||||
*/
|
||||
JSDOC.DocComment = function(/**String*/comment) {
|
||||
this.init();
|
||||
if (typeof comment != "undefined") {
|
||||
this.parse(comment);
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.DocComment.prototype.init = function() {
|
||||
this.isUserComment = true;
|
||||
this.src = "";
|
||||
this.meta = "";
|
||||
this.tagTexts = [];
|
||||
this.tags = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@requires JSDOC.DocTag
|
||||
*/
|
||||
JSDOC.DocComment.prototype.parse = function(/**String*/comment) {
|
||||
if (comment == "") {
|
||||
comment = "/** @desc */";
|
||||
this.isUserComment = false;
|
||||
}
|
||||
|
||||
this.src = JSDOC.DocComment.unwrapComment(comment);
|
||||
|
||||
this.meta = "";
|
||||
if (this.src.indexOf("#") == 0) {
|
||||
this.src.match(/#(.+[+-])([\s\S]*)$/);
|
||||
if (RegExp.$1) this.meta = RegExp.$1;
|
||||
if (RegExp.$2) this.src = RegExp.$2;
|
||||
}
|
||||
|
||||
if (typeof JSDOC.PluginManager != "undefined") {
|
||||
JSDOC.PluginManager.run("onDocCommentSrc", this);
|
||||
}
|
||||
|
||||
this.fixDesc();
|
||||
|
||||
this.src = JSDOC.DocComment.shared+"\n"+this.src;
|
||||
|
||||
this.tagTexts =
|
||||
this.src
|
||||
.split(/(^|[\r\n])\s*@/)
|
||||
.filter(function($){return $.match(/\S/)});
|
||||
|
||||
/**
|
||||
The tags found in the comment.
|
||||
@type JSDOC.DocTag[]
|
||||
*/
|
||||
this.tags = this.tagTexts.map(function($){return new JSDOC.DocTag($)});
|
||||
|
||||
if (typeof JSDOC.PluginManager != "undefined") {
|
||||
JSDOC.PluginManager.run("onDocCommentTags", this);
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(5, "testing JSDOC.DocComment");
|
||||
requires("../frame/String.js");
|
||||
requires("../lib/JSDOC/DocTag.js");
|
||||
|
||||
var com = new JSDOC.DocComment("/**@foo some\n* comment here*"+"/");
|
||||
is(com.tagTexts[0], "foo some\ncomment here", "first tag text is found.");
|
||||
is(com.tags[0].title, "foo", "the title is found in a comment with one tag.");
|
||||
|
||||
var com = new JSDOC.DocComment("/** @foo first\n* @bar second*"+"/");
|
||||
is(com.getTag("bar").length, 1, "getTag() returns one tag by that title.");
|
||||
|
||||
JSDOC.DocComment.shared = "@author John Smith";
|
||||
var com = new JSDOC.DocComment("/**@foo some\n* comment here*"+"/");
|
||||
is(com.tags[0].title, "author", "shared comment is added.");
|
||||
is(com.tags[1].title, "foo", "shared comment is added to existing tag.");
|
||||
*/
|
||||
|
||||
/**
|
||||
If no @desc tag is provided, this function will add it.
|
||||
*/
|
||||
JSDOC.DocComment.prototype.fixDesc = function() {
|
||||
if (this.meta && this.meta != "@+") return;
|
||||
if (/^\s*[^@\s]/.test(this.src)) {
|
||||
this.src = "@desc "+this.src;
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(5, "testing JSDOC.DocComment#fixDesc");
|
||||
|
||||
var com = new JSDOC.DocComment();
|
||||
|
||||
com.src = "this is a desc\n@author foo";
|
||||
com.fixDesc();
|
||||
is(com.src, "@desc this is a desc\n@author foo", "if no @desc tag is provided one is added.");
|
||||
|
||||
com.src = "x";
|
||||
com.fixDesc();
|
||||
is(com.src, "@desc x", "if no @desc tag is provided one is added to a single character.");
|
||||
|
||||
com.src = "\nx";
|
||||
com.fixDesc();
|
||||
is(com.src, "@desc \nx", "if no @desc tag is provided one is added to return and character.");
|
||||
|
||||
com.src = " ";
|
||||
com.fixDesc();
|
||||
is(com.src, " ", "if no @desc tag is provided one is not added to just whitespace.");
|
||||
|
||||
com.src = "";
|
||||
com.fixDesc();
|
||||
is(com.src, "", "if no @desc tag is provided one is not added to empty.");
|
||||
*/
|
||||
|
||||
/**
|
||||
Remove slash-star comment wrapper from a raw comment string.
|
||||
@type String
|
||||
*/
|
||||
JSDOC.DocComment.unwrapComment = function(/**String*/comment) {
|
||||
if (!comment) return "";
|
||||
var unwrapped = comment.replace(/(^\/\*\*|\*\/$)/g, "").replace(/^\s*\* ?/gm, "");
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(5, "testing JSDOC.DocComment.unwrapComment");
|
||||
|
||||
var com = "/**x*"+"/";
|
||||
var unwrapped = JSDOC.DocComment.unwrapComment(com);
|
||||
is(unwrapped, "x", "a single character jsdoc is found.");
|
||||
|
||||
com = "/***x*"+"/";
|
||||
unwrapped = JSDOC.DocComment.unwrapComment(com);
|
||||
is(unwrapped, "x", "three stars are allowed in the opener.");
|
||||
|
||||
com = "/****x*"+"/";
|
||||
unwrapped = JSDOC.DocComment.unwrapComment(com);
|
||||
is(unwrapped, "*x", "fourth star in the opener is kept.");
|
||||
|
||||
com = "/**x\n * y\n*"+"/";
|
||||
unwrapped = JSDOC.DocComment.unwrapComment(com);
|
||||
is(unwrapped, "x\ny\n", "leading stars and spaces are trimmed.");
|
||||
|
||||
com = "/**x\n * y\n*"+"/";
|
||||
unwrapped = JSDOC.DocComment.unwrapComment(com);
|
||||
is(unwrapped, "x\n y\n", "only first space after leading stars are trimmed.");
|
||||
*/
|
||||
|
||||
/**
|
||||
Provides a printable version of the comment.
|
||||
@type String
|
||||
*/
|
||||
JSDOC.DocComment.prototype.toString = function() {
|
||||
return this.src;
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(1, "testing JSDOC.DocComment#fixDesc");
|
||||
var com = new JSDOC.DocComment();
|
||||
com.src = "foo";
|
||||
is(""+com, "foo", "stringifying a comment returns the unwrapped src.");
|
||||
*/
|
||||
|
||||
/**
|
||||
Given the title of a tag, returns all tags that have that title.
|
||||
@type JSDOC.DocTag[]
|
||||
*/
|
||||
JSDOC.DocComment.prototype.getTag = function(/**String*/tagTitle) {
|
||||
return this.tags.filter(function($){return $.title == tagTitle});
|
||||
}
|
||||
|
||||
JSDOC.DocComment.prototype.deleteTag = function(/**String*/tagTitle) {
|
||||
this.tags = this.tags.filter(function($){return $.title != tagTitle})
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(1, "testing JSDOC.DocComment#getTag");
|
||||
requires("../frame/String.js");
|
||||
requires("../lib/JSDOC/DocTag.js");
|
||||
|
||||
var com = new JSDOC.DocComment("/**@foo some\n* @bar\n* @bar*"+"/");
|
||||
is(com.getTag("bar").length, 2, "getTag returns expected number of tags.");
|
||||
*/
|
||||
|
||||
/**
|
||||
Used to store the currently shared tag text.
|
||||
*/
|
||||
JSDOC.DocComment.shared = "";
|
||||
|
||||
/*t:
|
||||
plan(2, "testing JSDOC.DocComment.shared");
|
||||
requires("../frame/String.js");
|
||||
requires("../lib/JSDOC/DocTag.js");
|
||||
|
||||
JSDOC.DocComment.shared = "@author Michael";
|
||||
|
||||
var com = new JSDOC.DocComment("/**@foo\n* @foo*"+"/");
|
||||
is(com.getTag("author").length, 1, "getTag returns shared tag.");
|
||||
is(com.getTag("foo").length, 2, "getTag returns unshared tags too.");
|
||||
*/
|
|
@ -1,294 +0,0 @@
|
|||
if (typeof JSDOC == "undefined") JSDOC = {};
|
||||
|
||||
/**
|
||||
@constructor
|
||||
*/
|
||||
JSDOC.DocTag = function(src) {
|
||||
this.init();
|
||||
if (typeof src != "undefined") {
|
||||
this.parse(src);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Create and initialize the properties of this.
|
||||
*/
|
||||
JSDOC.DocTag.prototype.init = function() {
|
||||
this.title = "";
|
||||
this.type = "";
|
||||
this.name = "";
|
||||
this.isOptional = false;
|
||||
this.defaultValue = "";
|
||||
this.desc = "";
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
Populate the properties of this from the given tag src.
|
||||
@param {string} src
|
||||
*/
|
||||
JSDOC.DocTag.prototype.parse = function(src) {
|
||||
if (typeof src != "string") throw "src must be a string not "+(typeof src);
|
||||
|
||||
try {
|
||||
src = this.nibbleTitle(src);
|
||||
if (JSDOC.PluginManager) {
|
||||
JSDOC.PluginManager.run("onDocTagSynonym", this);
|
||||
}
|
||||
|
||||
src = this.nibbleType(src);
|
||||
|
||||
// only some tags are allowed to have names.
|
||||
if (this.title == "param" || this.title == "property" || this.title == "config") { // @config is deprecated
|
||||
src = this.nibbleName(src);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
if (LOG) LOG.warn(e);
|
||||
else throw e;
|
||||
}
|
||||
this.desc = src; // whatever is left
|
||||
|
||||
// example tags need to have whitespace preserved
|
||||
if (this.title != "example") this.desc = this.desc.trim();
|
||||
|
||||
if (JSDOC.PluginManager) {
|
||||
JSDOC.PluginManager.run("onDocTag", this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Automatically called when this is stringified.
|
||||
*/
|
||||
JSDOC.DocTag.prototype.toString = function() {
|
||||
return this.desc;
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(1, "testing JSDOC.DocTag#toString");
|
||||
|
||||
var tag = new JSDOC.DocTag("param {object} date A valid date.");
|
||||
is(""+tag, "A valid date.", "stringifying a tag returns the desc.");
|
||||
*/
|
||||
|
||||
/**
|
||||
Find and shift off the title of a tag.
|
||||
@param {string} src
|
||||
@return src
|
||||
*/
|
||||
JSDOC.DocTag.prototype.nibbleTitle = function(src) {
|
||||
if (typeof src != "string") throw "src must be a string not "+(typeof src);
|
||||
|
||||
var parts = src.match(/^\s*(\S+)(?:\s([\s\S]*))?$/);
|
||||
|
||||
if (parts && parts[1]) this.title = parts[1];
|
||||
if (parts && parts[2]) src = parts[2];
|
||||
else src = "";
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(8, "testing JSDOC.DocTag#nibbleTitle");
|
||||
|
||||
var tag = new JSDOC.DocTag();
|
||||
|
||||
tag.init().nibbleTitle("aTitleGoesHere");
|
||||
is(tag.title, "aTitleGoesHere", "a title can be found in a single-word string.");
|
||||
|
||||
var src = tag.init().nibbleTitle("aTitleGoesHere and the rest");
|
||||
is(tag.title, "aTitleGoesHere", "a title can be found in a multi-word string.");
|
||||
is(src, "and the rest", "the rest is returned when the title is nibbled off.");
|
||||
|
||||
src = tag.init().nibbleTitle("");
|
||||
is(tag.title, "", "given an empty string the title is empty.");
|
||||
is(src, "", "the rest is empty when the tag is empty.");
|
||||
|
||||
var src = tag.init().nibbleTitle(" aTitleGoesHere\n a description");
|
||||
is(tag.title, "aTitleGoesHere", "leading and trailing spaces are not part of the title.");
|
||||
is(src, " a description", "leading spaces (less one) are part of the description.");
|
||||
|
||||
tag.init().nibbleTitle("a.Title::Goes_Here foo");
|
||||
is(tag.title, "a.Title::Goes_Here", "titles with punctuation are allowed.");
|
||||
*/
|
||||
|
||||
/**
|
||||
Find and shift off the type of a tag.
|
||||
@requires frame/String.js
|
||||
@param {string} src
|
||||
@return src
|
||||
*/
|
||||
JSDOC.DocTag.prototype.nibbleType = function(src) {
|
||||
if (typeof src != "string") throw "src must be a string not "+(typeof src);
|
||||
|
||||
if (src.match(/^\s*\{/)) {
|
||||
var typeRange = src.balance("{", "}");
|
||||
if (typeRange[1] == -1) {
|
||||
throw "Malformed comment tag ignored. Tag type requires an opening { and a closing }: "+src;
|
||||
}
|
||||
this.type = src.substring(typeRange[0]+1, typeRange[1]).trim();
|
||||
this.type = this.type.replace(/\s*,\s*/g, "|"); // multiples can be separated by , or |
|
||||
src = src.substring(typeRange[1]+1);
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(5, "testing JSDOC.DocTag.parser.nibbleType");
|
||||
requires("../frame/String.js");
|
||||
|
||||
var tag = new JSDOC.DocTag();
|
||||
|
||||
tag.init().nibbleType("{String[]} aliases");
|
||||
is(tag.type, "String[]", "type can have non-alpha characters.");
|
||||
|
||||
tag.init().nibbleType("{ aTypeGoesHere } etc etc");
|
||||
is(tag.type, "aTypeGoesHere", "type is trimmed.");
|
||||
|
||||
tag.init().nibbleType("{ oneType, twoType ,\n threeType } etc etc");
|
||||
is(tag.type, "oneType|twoType|threeType", "multiple types can be separated by commas.");
|
||||
|
||||
var error;
|
||||
try { tag.init().nibbleType("{widget foo"); }
|
||||
catch(e) { error = e; }
|
||||
is(typeof error, "string", "malformed tag type throws error.");
|
||||
isnt(error.indexOf("Malformed"), -1, "error message tells tag is malformed.");
|
||||
*/
|
||||
|
||||
/**
|
||||
Find and shift off the name of a tag.
|
||||
@requires frame/String.js
|
||||
@param {string} src
|
||||
@return src
|
||||
*/
|
||||
JSDOC.DocTag.prototype.nibbleName = function(src) {
|
||||
if (typeof src != "string") throw "src must be a string not "+(typeof src);
|
||||
|
||||
src = src.trim();
|
||||
|
||||
// is optional?
|
||||
if (src.charAt(0) == "[") {
|
||||
var nameRange = src.balance("[", "]");
|
||||
if (nameRange[1] == -1) {
|
||||
throw "Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: "+src;
|
||||
}
|
||||
this.name = src.substring(nameRange[0]+1, nameRange[1]).trim();
|
||||
this.isOptional = true;
|
||||
|
||||
src = src.substring(nameRange[1]+1);
|
||||
|
||||
// has default value?
|
||||
var nameAndValue = this.name.split("=");
|
||||
if (nameAndValue.length) {
|
||||
this.name = nameAndValue.shift().trim();
|
||||
this.defaultValue = nameAndValue.join("=");
|
||||
}
|
||||
}
|
||||
else {
|
||||
var parts = src.match(/^(\S+)(?:\s([\s\S]*))?$/);
|
||||
if (parts) {
|
||||
if (parts[1]) this.name = parts[1];
|
||||
if (parts[2]) src = parts[2].trim();
|
||||
else src = "";
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
/*t:
|
||||
requires("../frame/String.js");
|
||||
plan(9, "testing JSDOC.DocTag.parser.nibbleName");
|
||||
|
||||
var tag = new JSDOC.DocTag();
|
||||
|
||||
tag.init().nibbleName("[foo] This is a description.");
|
||||
is(tag.isOptional, true, "isOptional syntax is detected.");
|
||||
is(tag.name, "foo", "optional param name is found.");
|
||||
|
||||
tag.init().nibbleName("[foo] This is a description.");
|
||||
is(tag.isOptional, true, "isOptional syntax is detected when no type.");
|
||||
is(tag.name, "foo", "optional param name is found when no type.");
|
||||
|
||||
tag.init().nibbleName("[foo=7] This is a description.");
|
||||
is(tag.name, "foo", "optional param name is found when default value.");
|
||||
is(tag.defaultValue, 7, "optional param default value is found when default value.");
|
||||
|
||||
//tag.init().nibbleName("[foo= a value] This is a description.");
|
||||
//is(tag.defaultValue, " a value", "optional param default value is found when default value has spaces (issue #112).");
|
||||
|
||||
tag.init().nibbleName("[foo=[]] This is a description.");
|
||||
is(tag.defaultValue, "[]", "optional param default value is found when default value is [] (issue #95).");
|
||||
|
||||
tag.init().nibbleName("[foo=a=b] This is a description.");
|
||||
is(tag.name, "foo", "optional param name is found when default value is a=b.");
|
||||
is(tag.defaultValue, "a=b", "optional param default value is found when default value is a=b.")
|
||||
*/
|
||||
|
||||
/*t:
|
||||
plan(32, "Testing JSDOC.DocTag.parser.");
|
||||
requires("../frame/String.js");
|
||||
|
||||
var tag = new JSDOC.DocTag();
|
||||
|
||||
is(typeof tag, "object", "JSDOC.DocTag.parser with an empty string returns an object.");
|
||||
is(typeof tag.title, "string", "returned object has a string property 'title'.");
|
||||
is(typeof tag.type, "string", "returned object has a string property 'type'.");
|
||||
is(typeof tag.name, "string", "returned object has a string property 'name'.");
|
||||
is(typeof tag.defaultValue, "string", "returned object has a string property 'defaultValue'.");
|
||||
is(typeof tag.isOptional, "boolean", "returned object has a boolean property 'isOptional'.");
|
||||
is(typeof tag.desc, "string", "returned object has a string property 'desc'.");
|
||||
|
||||
tag = new JSDOC.DocTag("param {widget} foo");
|
||||
is(tag.title, "param", "param title is found.");
|
||||
is(tag.name, "foo", "param name is found when desc is missing.");
|
||||
is(tag.desc, "", "param desc is empty when missing.");
|
||||
|
||||
tag = new JSDOC.DocTag("param {object} date A valid date.");
|
||||
is(tag.name, "date", "param name is found with a type.");
|
||||
is(tag.type, "object", "param type is found.");
|
||||
is(tag.desc, "A valid date.", "param desc is found with a type.");
|
||||
|
||||
tag = new JSDOC.DocTag("param aName a description goes\n here.");
|
||||
is(tag.name, "aName", "param name is found without a type.");
|
||||
is(tag.desc, "a description goes\n here.", "param desc is found without a type.");
|
||||
|
||||
tag = new JSDOC.DocTag("param {widget}");
|
||||
is(tag.name, "", "param name is empty when it is not given.");
|
||||
|
||||
tag = new JSDOC.DocTag("param {widget} [foo] This is a description.");
|
||||
is(tag.name, "foo", "optional param name is found.");
|
||||
|
||||
tag = new JSDOC.DocTag("return {aType} This is a description.");
|
||||
is(tag.type, "aType", "when return tag has no name, type is found.");
|
||||
is(tag.desc, "This is a description.", "when return tag has no name, desc is found.");
|
||||
|
||||
tag = new JSDOC.DocTag("author Joe Coder <jcoder@example.com>");
|
||||
is(tag.title, "author", "author tag has a title.");
|
||||
is(tag.type, "", "the author tag has no type.");
|
||||
is(tag.name, "", "the author tag has no name.");
|
||||
is(tag.desc, "Joe Coder <jcoder@example.com>", "author tag has desc.");
|
||||
|
||||
tag = new JSDOC.DocTag("private \t\n ");
|
||||
is(tag.title, "private", "private tag has a title.");
|
||||
is(tag.type, "", "the private tag has no type.");
|
||||
is(tag.name, "", "the private tag has no name.");
|
||||
is(tag.desc, "", "private tag has no desc.");
|
||||
|
||||
tag = new JSDOC.DocTag("example\n example(code);\n more();");
|
||||
is(tag.desc, " example(code);\n more();", "leading whitespace (less one) in examples code is preserved.");
|
||||
|
||||
tag = new JSDOC.DocTag("param theName \n");
|
||||
is(tag.name, "theName", "name only is found.");
|
||||
|
||||
tag = new JSDOC.DocTag("type theDesc \n");
|
||||
is(tag.desc, "theDesc", "desc only is found.");
|
||||
|
||||
tag = new JSDOC.DocTag("type {theType} \n");
|
||||
is(tag.type, "theType", "type only is found.");
|
||||
|
||||
tag = new JSDOC.DocTag("");
|
||||
is(tag.title, "", "title is empty when tag is empty.");
|
||||
*/
|
|
@ -1,126 +0,0 @@
|
|||
/**
|
||||
@constructor
|
||||
@param [opt] Used to override the commandline options. Useful for testing.
|
||||
@version $Id: JsDoc.js 773 2009-01-24 09:42:04Z micmath $
|
||||
*/
|
||||
JSDOC.JsDoc = function(/**object*/ opt) {
|
||||
if (opt) {
|
||||
JSDOC.opt = opt;
|
||||
}
|
||||
|
||||
if (JSDOC.opt.h) {
|
||||
JSDOC.usage();
|
||||
quit();
|
||||
}
|
||||
|
||||
// defend against options that are not sane
|
||||
if (JSDOC.opt._.length == 0) {
|
||||
LOG.warn("No source files to work on. Nothing to do.");
|
||||
quit();
|
||||
}
|
||||
if (JSDOC.opt.t === true || JSDOC.opt.d === true) {
|
||||
JSDOC.usage();
|
||||
}
|
||||
|
||||
if (typeof JSDOC.opt.d == "string") {
|
||||
if (!JSDOC.opt.d.charAt(JSDOC.opt.d.length-1).match(/[\\\/]/)) {
|
||||
JSDOC.opt.d = JSDOC.opt.d+"/";
|
||||
}
|
||||
LOG.inform("Output directory set to '"+JSDOC.opt.d+"'.");
|
||||
IO.mkPath(JSDOC.opt.d);
|
||||
}
|
||||
if (JSDOC.opt.e) IO.setEncoding(JSDOC.opt.e);
|
||||
|
||||
// the -r option: scan source directories recursively
|
||||
if (typeof JSDOC.opt.r == "boolean") JSDOC.opt.r = 10;
|
||||
else if (!isNaN(parseInt(JSDOC.opt.r))) JSDOC.opt.r = parseInt(JSDOC.opt.r);
|
||||
else JSDOC.opt.r = 1;
|
||||
|
||||
// the -D option: define user variables
|
||||
var D = {};
|
||||
if (JSDOC.opt.D) {
|
||||
for (var i = 0; i < JSDOC.opt.D.length; i++) {
|
||||
var defineParts = JSDOC.opt.D[i].split(":", 2);
|
||||
if (defineParts) D[defineParts[0]] = defineParts[1];
|
||||
}
|
||||
}
|
||||
JSDOC.opt.D = D;
|
||||
// combine any conf file D options with the commandline D options
|
||||
if (defined(JSDOC.conf)) for (var c in JSDOC.conf.D) {
|
||||
if (!defined(JSDOC.opt.D[c])) {
|
||||
JSDOC.opt.D[c] = JSDOC.conf.D[c];
|
||||
}
|
||||
}
|
||||
|
||||
// Give plugins a chance to initialize
|
||||
if (defined(JSDOC.PluginManager)) {
|
||||
JSDOC.PluginManager.run("onInit", JSDOC.opt);
|
||||
}
|
||||
|
||||
JSDOC.opt.srcFiles = JSDOC.JsDoc._getSrcFiles();
|
||||
JSDOC.JsDoc._parseSrcFiles();
|
||||
JSDOC.JsDoc.symbolSet = JSDOC.Parser.symbols;
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieve source file list.
|
||||
@returns {String[]} The pathnames of the files to be parsed.
|
||||
*/
|
||||
JSDOC.JsDoc._getSrcFiles = function() {
|
||||
JSDOC.JsDoc.srcFiles = [];
|
||||
|
||||
var ext = ["js"];
|
||||
if (JSDOC.opt.x) {
|
||||
ext = JSDOC.opt.x.split(",").map(function($) {return $.toLowerCase()});
|
||||
}
|
||||
|
||||
for (var i = 0; i < JSDOC.opt._.length; i++) {
|
||||
JSDOC.JsDoc.srcFiles = JSDOC.JsDoc.srcFiles.concat(
|
||||
IO.ls(JSDOC.opt._[i], JSDOC.opt.r).filter(
|
||||
function($) {
|
||||
var thisExt = $.split(".").pop().toLowerCase();
|
||||
|
||||
if (JSDOC.opt.E) {
|
||||
for(var n = 0; n < JSDOC.opt.E.length; n++) {
|
||||
if ($.match(new RegExp(JSDOC.opt.E[n]))) {
|
||||
LOG.inform("Excluding " + $);
|
||||
return false; // if the file matches the regex then it's excluded.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (ext.indexOf(thisExt) > -1); // we're only interested in files with certain extensions
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return JSDOC.JsDoc.srcFiles;
|
||||
}
|
||||
|
||||
JSDOC.JsDoc._parseSrcFiles = function() {
|
||||
JSDOC.Parser.init();
|
||||
for (var i = 0, l = JSDOC.JsDoc.srcFiles.length; i < l; i++) {
|
||||
var srcFile = JSDOC.JsDoc.srcFiles[i];
|
||||
|
||||
if (JSDOC.opt.v) LOG.inform("Parsing file: " + srcFile);
|
||||
|
||||
try {
|
||||
var src = IO.readFile(srcFile);
|
||||
}
|
||||
catch(e) {
|
||||
LOG.warn("Can't read source file '"+srcFile+"': "+e.message);
|
||||
}
|
||||
|
||||
var tr = new JSDOC.TokenReader();
|
||||
var ts = new JSDOC.TokenStream(tr.tokenize(new JSDOC.TextStream(src)));
|
||||
|
||||
JSDOC.Parser.parse(ts, srcFile);
|
||||
|
||||
}
|
||||
JSDOC.Parser.finish();
|
||||
|
||||
if (JSDOC.PluginManager) {
|
||||
JSDOC.PluginManager.run("onFinishedParsing", JSDOC.Parser.symbols);
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/**
|
||||
@constructor
|
||||
*/
|
||||
JSDOC.JsPlate = function(templateFile) {
|
||||
if (templateFile) this.template = IO.readFile(templateFile);
|
||||
|
||||
this.templateFile = templateFile;
|
||||
this.code = "";
|
||||
this.parse();
|
||||
}
|
||||
|
||||
JSDOC.JsPlate.prototype.parse = function() {
|
||||
this.template = this.template.replace(/\{#[\s\S]+?#\}/gi, "");
|
||||
this.code = "var output=\u001e"+this.template;
|
||||
|
||||
this.code = this.code.replace(
|
||||
/<for +each="(.+?)" +in="(.+?)" *>/gi,
|
||||
function (match, eachName, inName) {
|
||||
return "\u001e;\rvar $"+eachName+"_keys = keys("+inName+");\rfor(var $"+eachName+"_i = 0; $"+eachName+"_i < $"+eachName+"_keys.length; $"+eachName+"_i++) {\rvar $"+eachName+"_last = ($"+eachName+"_i == $"+eachName+"_keys.length-1);\rvar $"+eachName+"_key = $"+eachName+"_keys[$"+eachName+"_i];\rvar "+eachName+" = "+inName+"[$"+eachName+"_key];\routput+=\u001e";
|
||||
}
|
||||
);
|
||||
this.code = this.code.replace(/<if test="(.+?)">/g, "\u001e;\rif ($1) { output+=\u001e");
|
||||
this.code = this.code.replace(/<elseif test="(.+?)"\s*\/>/g, "\u001e;}\relse if ($1) { output+=\u001e");
|
||||
this.code = this.code.replace(/<else\s*\/>/g, "\u001e;}\relse { output+=\u001e");
|
||||
this.code = this.code.replace(/<\/(if|for)>/g, "\u001e;\r};\routput+=\u001e");
|
||||
this.code = this.code.replace(
|
||||
/\{\+\s*([\s\S]+?)\s*\+\}/gi,
|
||||
function (match, code) {
|
||||
code = code.replace(/"/g, "\u001e"); // prevent qoute-escaping of inline code
|
||||
code = code.replace(/(\r?\n)/g, " ");
|
||||
return "\u001e+ ("+code+") +\u001e";
|
||||
}
|
||||
);
|
||||
this.code = this.code.replace(
|
||||
/\{!\s*([\s\S]+?)\s*!\}/gi,
|
||||
function (match, code) {
|
||||
code = code.replace(/"/g, "\u001e"); // prevent qoute-escaping of inline code
|
||||
code = code.replace(/(\n)/g, " ");
|
||||
return "\u001e; "+code+";\routput+=\u001e";
|
||||
}
|
||||
);
|
||||
this.code = this.code+"\u001e;";
|
||||
|
||||
this.code = this.code.replace(/(\r?\n)/g, "\\n");
|
||||
this.code = this.code.replace(/"/g, "\\\"");
|
||||
this.code = this.code.replace(/\u001e/g, "\"");
|
||||
}
|
||||
|
||||
JSDOC.JsPlate.prototype.toCode = function() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
JSDOC.JsPlate.keys = function(obj) {
|
||||
var keys = [];
|
||||
if (obj.constructor.toString().indexOf("Array") > -1) {
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
keys.push(i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i in obj) {
|
||||
keys.push(i);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
};
|
||||
|
||||
JSDOC.JsPlate.values = function(obj) {
|
||||
var values = [];
|
||||
if (obj.constructor.toString().indexOf("Array") > -1) {
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
values.push(obj[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i in obj) {
|
||||
values.push(obj[i]);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
};
|
||||
|
||||
JSDOC.JsPlate.prototype.process = function(data, compact) {
|
||||
var keys = JSDOC.JsPlate.keys;
|
||||
var values = JSDOC.JsPlate.values;
|
||||
|
||||
try {
|
||||
eval(this.code);
|
||||
}
|
||||
catch (e) {
|
||||
print(">> There was an error evaluating the compiled code from template: "+this.templateFile);
|
||||
print(" The error was on line "+e.lineNumber+" "+e.name+": "+e.message);
|
||||
var lines = this.code.split("\r");
|
||||
if (e.lineNumber-2 >= 0) print("line "+(e.lineNumber-1)+": "+lines[e.lineNumber-2]);
|
||||
print("line "+e.lineNumber+": "+lines[e.lineNumber-1]);
|
||||
print("");
|
||||
}
|
||||
|
||||
if (compact) { // patch by mcbain.asm
|
||||
// Remove lines that contain only space-characters, usually left by lines in the template
|
||||
// which originally only contained JSPlate tags or code. This makes it easier to write
|
||||
// non-tricky templates which still put out nice code (not bloated with extra lines).
|
||||
// Lines purposely left blank (just a line ending) are left alone.
|
||||
output = output.replace(/\s+?(\r?)\n/g, "$1\n");
|
||||
}
|
||||
|
||||
/*debug*///print(this.code);
|
||||
return output;
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/**
|
||||
@namespace
|
||||
*/
|
||||
JSDOC.Lang = {
|
||||
}
|
||||
|
||||
JSDOC.Lang.isBuiltin = function(name) {
|
||||
return (JSDOC.Lang.isBuiltin.coreObjects.indexOf(name) > -1);
|
||||
}
|
||||
JSDOC.Lang.isBuiltin.coreObjects = ['_global_', 'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object', 'RegExp', 'String'];
|
||||
|
||||
JSDOC.Lang.whitespace = function(ch) {
|
||||
return JSDOC.Lang.whitespace.names[ch];
|
||||
}
|
||||
JSDOC.Lang.whitespace.names = {
|
||||
" ": "SPACE",
|
||||
"\f": "FORMFEED",
|
||||
"\t": "TAB",
|
||||
"\u0009": "UNICODE_TAB",
|
||||
"\u000A": "UNICODE_NBR",
|
||||
"\u0008": "VERTICAL_TAB"
|
||||
};
|
||||
|
||||
JSDOC.Lang.newline = function(ch) {
|
||||
return JSDOC.Lang.newline.names[ch];
|
||||
}
|
||||
JSDOC.Lang.newline.names = {
|
||||
"\n": "NEWLINE",
|
||||
"\r": "RETURN",
|
||||
"\u000A": "UNICODE_LF",
|
||||
"\u000D": "UNICODE_CR",
|
||||
"\u2029": "UNICODE_PS",
|
||||
"\u2028": "UNICODE_LS"
|
||||
};
|
||||
|
||||
JSDOC.Lang.keyword = function(word) {
|
||||
return JSDOC.Lang.keyword.names["="+word];
|
||||
}
|
||||
JSDOC.Lang.keyword.names = {
|
||||
"=break": "BREAK",
|
||||
"=case": "CASE",
|
||||
"=catch": "CATCH",
|
||||
"=const": "VAR",
|
||||
"=continue": "CONTINUE",
|
||||
"=default": "DEFAULT",
|
||||
"=delete": "DELETE",
|
||||
"=do": "DO",
|
||||
"=else": "ELSE",
|
||||
"=false": "FALSE",
|
||||
"=finally": "FINALLY",
|
||||
"=for": "FOR",
|
||||
"=function": "FUNCTION",
|
||||
"=if": "IF",
|
||||
"=in": "IN",
|
||||
"=instanceof": "INSTANCEOF",
|
||||
"=new": "NEW",
|
||||
"=null": "NULL",
|
||||
"=return": "RETURN",
|
||||
"=switch": "SWITCH",
|
||||
"=this": "THIS",
|
||||
"=throw": "THROW",
|
||||
"=true": "TRUE",
|
||||
"=try": "TRY",
|
||||
"=typeof": "TYPEOF",
|
||||
"=void": "VOID",
|
||||
"=while": "WHILE",
|
||||
"=with": "WITH",
|
||||
"=var": "VAR"
|
||||
};
|
||||
|
||||
JSDOC.Lang.punc = function(ch) {
|
||||
return JSDOC.Lang.punc.names[ch];
|
||||
}
|
||||
JSDOC.Lang.punc.names = {
|
||||
";": "SEMICOLON",
|
||||
",": "COMMA",
|
||||
"?": "HOOK",
|
||||
":": "COLON",
|
||||
"||": "OR",
|
||||
"&&": "AND",
|
||||
"|": "BITWISE_OR",
|
||||
"^": "BITWISE_XOR",
|
||||
"&": "BITWISE_AND",
|
||||
"===": "STRICT_EQ",
|
||||
"==": "EQ",
|
||||
"=": "ASSIGN",
|
||||
"!==": "STRICT_NE",
|
||||
"!=": "NE",
|
||||
"<<": "LSH",
|
||||
"<=": "LE",
|
||||
"<": "LT",
|
||||
">>>": "URSH",
|
||||
">>": "RSH",
|
||||
">=": "GE",
|
||||
">": "GT",
|
||||
"++": "INCREMENT",
|
||||
"--": "DECREMENT",
|
||||
"+": "PLUS",
|
||||
"-": "MINUS",
|
||||
"*": "MUL",
|
||||
"/": "DIV",
|
||||
"%": "MOD",
|
||||
"!": "NOT",
|
||||
"~": "BITWISE_NOT",
|
||||
".": "DOT",
|
||||
"[": "LEFT_BRACKET",
|
||||
"]": "RIGHT_BRACKET",
|
||||
"{": "LEFT_CURLY",
|
||||
"}": "RIGHT_CURLY",
|
||||
"(": "LEFT_PAREN",
|
||||
")": "RIGHT_PAREN"
|
||||
};
|
||||
|
||||
JSDOC.Lang.matching = function(name) {
|
||||
return JSDOC.Lang.matching.names[name];
|
||||
}
|
||||
JSDOC.Lang.matching.names = {
|
||||
"LEFT_PAREN": "RIGHT_PAREN",
|
||||
"RIGHT_PAREN": "LEFT_PAREN",
|
||||
"LEFT_CURLY": "RIGHT_CURLY",
|
||||
"RIGHT_CURLY": "LEFT_CURLY",
|
||||
"LEFT_BRACE": "RIGHT_BRACE",
|
||||
"RIGHT_BRACE": "LEFT_BRACE"
|
||||
}
|
||||
|
||||
JSDOC.Lang.isNumber = function(str) {
|
||||
return /^(\.[0-9]|[0-9]+\.|[0-9])[0-9]*([eE][+-][0-9]+)?$/i.test(str);
|
||||
}
|
||||
|
||||
JSDOC.Lang.isHexDec = function(str) {
|
||||
return /^0x[0-9A-F]+$/i.test(str);
|
||||
}
|
||||
|
||||
JSDOC.Lang.isWordChar = function(str) {
|
||||
return /^[a-zA-Z0-9$_.]+$/.test(str);
|
||||
}
|
||||
|
||||
JSDOC.Lang.isSpace = function(str) {
|
||||
return (typeof JSDOC.Lang.whitespace(str) != "undefined");
|
||||
}
|
||||
|
||||
JSDOC.Lang.isNewline = function(str) {
|
||||
return (typeof JSDOC.Lang.newline(str) != "undefined");
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
if (typeof JSDOC == "undefined") JSDOC = {};
|
||||
|
||||
/**
|
||||
@namespace
|
||||
@requires JSDOC.Walker
|
||||
@requires JSDOC.Symbol
|
||||
@requires JSDOC.DocComment
|
||||
*/
|
||||
JSDOC.Parser = {
|
||||
conf: {
|
||||
ignoreCode: JSDOC.opt.n,
|
||||
ignoreAnonymous: true, // factory: true
|
||||
treatUnderscoredAsPrivate: true, // factory: true
|
||||
explain: false // factory: false
|
||||
},
|
||||
|
||||
addSymbol: function(symbol) {
|
||||
|
||||
if (JSDOC.Parser.rename) {
|
||||
for (var n in JSDOC.Parser.rename) {
|
||||
if (symbol.alias.indexOf(n) == 0) {
|
||||
if (symbol.name == symbol.alias) {
|
||||
symbol.name = symbol.name.replace(n, JSDOC.Parser.rename[n]);
|
||||
}
|
||||
symbol.alias = symbol.alias.replace(n, JSDOC.Parser.rename[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (JSDOC.opt.S) {
|
||||
if (typeof JSDOC.Parser.secureModules == "undefined") JSDOC.Parser.secureModules = {};
|
||||
if (/^exports\./.test(symbol.alias)) {
|
||||
symbol.srcFile.match(/(^|[\\\/])([^\\\/]+)\.js/i);
|
||||
var fileNS = RegExp.$2;
|
||||
|
||||
// need to create the namespace associated with this file first
|
||||
if (!JSDOC.Parser.secureModules[fileNS]) {
|
||||
JSDOC.Parser.secureModules[fileNS] = 1;
|
||||
var nsSymbol = new JSDOC.Symbol(fileNS, [], "GLOBAL", new JSDOC.DocComment(""));
|
||||
nsSymbol.isNamespace = true;
|
||||
nsSymbol.srcFile = "";
|
||||
nsSymbol.isPrivate = false;
|
||||
nsSymbol.srcFile = symbol.srcFile;
|
||||
nsSymbol.desc = (JSDOC.Parser.symbols.getSymbol(symbol.srcFile) || {desc: ""}).desc;
|
||||
JSDOC.Parser.addSymbol(nsSymbol);
|
||||
}
|
||||
|
||||
symbol.alias = symbol.alias.replace(/^exports\./, fileNS + '.');
|
||||
symbol.name = symbol.name.replace(/^exports\./, '');
|
||||
symbol.memberOf = fileNS;
|
||||
symbol.isStatic = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if a symbol alias is documented more than once the last one with the user docs wins
|
||||
if (JSDOC.Parser.symbols.hasSymbol(symbol.alias)) {
|
||||
var oldSymbol = JSDOC.Parser.symbols.getSymbol(symbol.alias);
|
||||
if (oldSymbol.comment.isUserComment) {
|
||||
if (symbol.comment.isUserComment) { // old and new are both documented
|
||||
LOG.warn("The symbol '"+symbol.alias+"' is documented more than once.");
|
||||
}
|
||||
else { // old is documented but new isn't
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we don't document anonymous things
|
||||
if (JSDOC.Parser.conf.ignoreAnonymous && symbol.name.match(/\$anonymous\b/)) return;
|
||||
|
||||
// uderscored things may be treated as if they were marked private, this cascades
|
||||
if (JSDOC.Parser.conf.treatUnderscoredAsPrivate && symbol.name.match(/[.#-]_[^.#-]+$/)) {
|
||||
if (!symbol.comment.getTag("public").length > 0) symbol.isPrivate = true;
|
||||
}
|
||||
|
||||
// -p flag is required to document private things
|
||||
if (!JSDOC.opt.p && symbol.isPrivate) return; // issue #161 fixed by mcbain.asm
|
||||
|
||||
// ignored things are not documented, this doesn't cascade
|
||||
if (symbol.isIgnored) return;
|
||||
JSDOC.Parser.symbols.addSymbol(symbol);
|
||||
},
|
||||
|
||||
addBuiltin: function(name) {
|
||||
var builtin = new JSDOC.Symbol(name, [], "CONSTRUCTOR", new JSDOC.DocComment(""));
|
||||
builtin.isNamespace = true;
|
||||
builtin.srcFile = "";
|
||||
builtin.isPrivate = false;
|
||||
JSDOC.Parser.addSymbol(builtin);
|
||||
return builtin;
|
||||
},
|
||||
|
||||
init: function() {
|
||||
JSDOC.Parser.symbols = new JSDOC.SymbolSet();
|
||||
JSDOC.Parser.walker = new JSDOC.Walker();
|
||||
},
|
||||
|
||||
finish: function() {
|
||||
JSDOC.Parser.symbols.relate();
|
||||
|
||||
// make a litle report about what was found
|
||||
if (JSDOC.Parser.conf.explain) {
|
||||
var symbols = JSDOC.Parser.symbols.toArray();
|
||||
var srcFile = "";
|
||||
for (var i = 0, l = symbols.length; i < l; i++) {
|
||||
var symbol = symbols[i];
|
||||
if (srcFile != symbol.srcFile) {
|
||||
srcFile = symbol.srcFile;
|
||||
print("\n"+srcFile+"\n-------------------");
|
||||
}
|
||||
print(i+":\n alias => "+symbol.alias + "\n name => "+symbol.name+ "\n isa => "+symbol.isa + "\n memberOf => " + symbol.memberOf + "\n isStatic => " + symbol.isStatic + ", isInner => " + symbol.isInner+ ", isPrivate => " + symbol.isPrivate);
|
||||
}
|
||||
print("-------------------\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.Parser.parse = function(/**JSDOC.TokenStream*/ts, /**String*/srcFile) {
|
||||
JSDOC.Symbol.srcFile = (srcFile || "");
|
||||
JSDOC.DocComment.shared = ""; // shared comments don't cross file boundaries
|
||||
|
||||
if (!JSDOC.Parser.walker) JSDOC.Parser.init();
|
||||
JSDOC.Parser.walker.walk(ts); // adds to our symbols
|
||||
|
||||
// filter symbols by option
|
||||
for (var p = JSDOC.Parser.symbols._index.first(); p; p = JSDOC.Parser.symbols._index.next()) {
|
||||
var symbol = p.value;
|
||||
|
||||
if (!symbol) continue;
|
||||
|
||||
if (symbol.is("FILE") || symbol.is("GLOBAL")) {
|
||||
continue;
|
||||
}
|
||||
else if (!JSDOC.opt.a && !symbol.comment.isUserComment) {
|
||||
JSDOC.Parser.symbols.deleteSymbol(symbol.alias);
|
||||
}
|
||||
|
||||
if (/#$/.test(symbol.alias)) { // we don't document prototypes
|
||||
JSDOC.Parser.symbols.deleteSymbol(symbol.alias);
|
||||
}
|
||||
}
|
||||
|
||||
return JSDOC.Parser.symbols.toArray();
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/**
|
||||
@namespace Holds functionality related to running plugins.
|
||||
*/
|
||||
JSDOC.PluginManager = {
|
||||
}
|
||||
|
||||
/**
|
||||
@param name A unique name that identifies that plugin.
|
||||
@param handlers A collection of named functions. The names correspond to hooks in the core code.
|
||||
*/
|
||||
JSDOC.PluginManager.registerPlugin = function(/**String*/name, /**Object*/handlers) {
|
||||
if (!defined(JSDOC.PluginManager.plugins))
|
||||
/** The collection of all plugins. Requires a unique name for each.
|
||||
*/
|
||||
JSDOC.PluginManager.plugins = {};
|
||||
|
||||
|
||||
JSDOC.PluginManager.plugins[name] = handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
@param hook The name of the hook that is being caught.
|
||||
@param target Any object. This will be passed as the only argument to the handler whose
|
||||
name matches the hook name. Handlers cannot return a value, so must modify the target
|
||||
object to have an effect.
|
||||
*/
|
||||
JSDOC.PluginManager.run = function(/**String*/hook, /**Mixed*/target) {
|
||||
for (var name in JSDOC.PluginManager.plugins) {
|
||||
if (defined(JSDOC.PluginManager.plugins[name][hook])) {
|
||||
JSDOC.PluginManager.plugins[name][hook](target);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,644 +0,0 @@
|
|||
if (typeof JSDOC == "undefined") JSDOC = {};
|
||||
|
||||
/**
|
||||
Create a new Symbol.
|
||||
@class Represents a symbol in the source code.
|
||||
*/
|
||||
JSDOC.Symbol = function() {
|
||||
this.init();
|
||||
if (arguments.length) this.populate.apply(this, arguments);
|
||||
}
|
||||
|
||||
JSDOC.Symbol.count = 0;
|
||||
|
||||
JSDOC.Symbol.prototype.init = function() {
|
||||
this._name = "";
|
||||
this._params = [];
|
||||
this.$args = [];
|
||||
this.addOn = "";
|
||||
this.alias = "";
|
||||
this.augments = [];
|
||||
this.author = "";
|
||||
this.classDesc = "";
|
||||
this.comment = {};
|
||||
this.defaultValue = undefined;
|
||||
this.deprecated = "";
|
||||
this.desc = "";
|
||||
this.example = [];
|
||||
this.exceptions = [];
|
||||
this.fires = [];
|
||||
this.id = JSDOC.Symbol.count++;
|
||||
this.inherits = [];
|
||||
this.inheritsFrom = [];
|
||||
this.isa = "OBJECT";
|
||||
this.isConstant = false;
|
||||
this.isEvent = false;
|
||||
this.isIgnored = false;
|
||||
this.isInner = false;
|
||||
this.isNamespace = false;
|
||||
this.isPrivate = false;
|
||||
this.isStatic = false;
|
||||
this.memberOf = "";
|
||||
this.methods = [];
|
||||
this.properties = [];
|
||||
this.requires = [];
|
||||
this.returns = [];
|
||||
this.see = [];
|
||||
this.since = "";
|
||||
this.srcFile = {};
|
||||
this.type = "";
|
||||
this.version = "";
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.serialize = function() {
|
||||
var keys = [];
|
||||
for (var p in this) {
|
||||
keys.push (p);
|
||||
}
|
||||
keys = keys.sort();
|
||||
|
||||
var out = "";
|
||||
for (var i in keys) {
|
||||
if (typeof this[keys[i]] == "function") continue;
|
||||
out += keys[i]+" => "+Dumper.dump(this[keys[i]])+",\n";
|
||||
}
|
||||
return "\n{\n" + out + "}\n";
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.clone = function() {
|
||||
var clone = new JSDOC.Symbol();
|
||||
clone.populate.apply(clone, this.$args); // repopulate using the original arguments
|
||||
clone.srcFile = this.srcFile; // not the current srcFile, the one when the original was made
|
||||
return clone;
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.__defineSetter__("name",
|
||||
function(n) { n = n.replace(/^_global_[.#-]/, ""); n = n.replace(/\.prototype\.?/g, '#'); this._name = n; }
|
||||
);
|
||||
JSDOC.Symbol.prototype.__defineGetter__("name",
|
||||
function() { return this._name; }
|
||||
);
|
||||
JSDOC.Symbol.prototype.__defineSetter__("params",
|
||||
function(v) {
|
||||
for (var i = 0, l = v.length; i < l; i++) {
|
||||
if (v[i].constructor != JSDOC.DocTag) { // may be a generic object parsed from signature, like {type:..., name:...}
|
||||
this._params[i] = new JSDOC.DocTag("param"+((v[i].type)?" {"+v[i].type+"}":"")+" "+v[i].name);
|
||||
}
|
||||
else {
|
||||
this._params[i] = v[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
JSDOC.Symbol.prototype.__defineGetter__("params",
|
||||
function() { return this._params; }
|
||||
);
|
||||
|
||||
JSDOC.Symbol.prototype.getEvents = function() {
|
||||
var events = [];
|
||||
for (var i = 0, l = this.methods.length; i < l; i++) {
|
||||
if (this.methods[i].isEvent) {
|
||||
this.methods[i].name = this.methods[i].name.replace("event:", "");
|
||||
events.push(this.methods[i]);
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.getMethods = function() {
|
||||
var nonEvents = [];
|
||||
for (var i = 0, l = this.methods.length; i < l; i++) {
|
||||
if (!this.methods[i].isEvent) {
|
||||
nonEvents.push(this.methods[i]);
|
||||
}
|
||||
}
|
||||
return nonEvents;
|
||||
}
|
||||
|
||||
|
||||
JSDOC.Symbol.prototype.populate = function(
|
||||
/** String */ name,
|
||||
/** Object[] */ params,
|
||||
/** String */ isa,
|
||||
/** JSDOC.DocComment */ comment
|
||||
) {
|
||||
this.$args = arguments;
|
||||
|
||||
this.name = name;
|
||||
this.alias = this.name;
|
||||
|
||||
this.params = params;
|
||||
this.isa = (isa == "VIRTUAL")? "OBJECT":isa;
|
||||
this.comment = comment || new JSDOC.DocComment("");
|
||||
this.srcFile = JSDOC.Symbol.srcFile;
|
||||
|
||||
if (this.is("FILE") && !this.alias) this.alias = this.srcFile;
|
||||
|
||||
this.setTags();
|
||||
|
||||
if (typeof JSDOC.PluginManager != "undefined") {
|
||||
JSDOC.PluginManager.run("onSymbol", this);
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.setTags = function() {
|
||||
// @author
|
||||
var authors = this.comment.getTag("author");
|
||||
if (authors.length) {
|
||||
this.author = authors.map(function($){return $.desc;}).join(", ");
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(34, "testing JSDOC.Symbol");
|
||||
|
||||
requires("../lib/JSDOC/DocComment.js");
|
||||
requires("../frame/String.js");
|
||||
requires("../lib/JSDOC/DocTag.js");
|
||||
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@author Joe Smith*"+"/"));
|
||||
is(sym.author, "Joe Smith", "@author tag, author is found.");
|
||||
*/
|
||||
|
||||
// @desc
|
||||
var descs = this.comment.getTag("desc");
|
||||
if (descs.length) {
|
||||
this.desc = descs.map(function($){return $.desc;}).join("\n"); // multiple descriptions are concatenated into one
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@desc This is a description.*"+"/"));
|
||||
is(sym.desc, "This is a description.", "@desc tag, description is found.");
|
||||
*/
|
||||
|
||||
// @overview
|
||||
if (this.is("FILE")) {
|
||||
if (!this.alias) this.alias = this.srcFile;
|
||||
|
||||
var overviews = this.comment.getTag("overview");
|
||||
if (overviews.length) {
|
||||
this.desc = [this.desc].concat(overviews.map(function($){return $.desc;})).join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@overview This is an overview.*"+"/"));
|
||||
is(sym.desc, "\nThis is an overview.", "@overview tag, description is found.");
|
||||
*/
|
||||
|
||||
// @since
|
||||
var sinces = this.comment.getTag("since");
|
||||
if (sinces.length) {
|
||||
this.since = sinces.map(function($){return $.desc;}).join(", ");
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@since 1.01*"+"/"));
|
||||
is(sym.since, "1.01", "@since tag, description is found.");
|
||||
*/
|
||||
|
||||
// @constant
|
||||
if (this.comment.getTag("constant").length) {
|
||||
this.isConstant = true;
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@constant*"+"/"));
|
||||
is(sym.isConstant, true, "@constant tag, isConstant set.");
|
||||
*/
|
||||
|
||||
// @version
|
||||
var versions = this.comment.getTag("version");
|
||||
if (versions.length) {
|
||||
this.version = versions.map(function($){return $.desc;}).join(", ");
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@version 2.0x*"+"/"));
|
||||
is(sym.version, "2.0x", "@version tag, version is found.");
|
||||
*/
|
||||
|
||||
// @deprecated
|
||||
var deprecateds = this.comment.getTag("deprecated");
|
||||
if (deprecateds.length) {
|
||||
this.deprecated = deprecateds.map(function($){return $.desc;}).join("\n");
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@deprecated Use other method.*"+"/"));
|
||||
is(sym.deprecated, "Use other method.", "@deprecated tag, desc is found.");
|
||||
*/
|
||||
|
||||
// @example
|
||||
var examples = this.comment.getTag("example");
|
||||
if (examples.length) {
|
||||
this.example = examples.map(
|
||||
// trim trailing whitespace
|
||||
function($) {
|
||||
$.desc = $.desc.replace(/\s+$/, "");
|
||||
return $;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@example This\n is an example. \n*"+"/"));
|
||||
isnt(typeof sym.example[0], "undefined", "@example tag, creates sym.example array.");
|
||||
is(sym.example[0], "This\n is an example.", "@example tag, desc is found.");
|
||||
*/
|
||||
|
||||
// @see
|
||||
var sees = this.comment.getTag("see");
|
||||
if (sees.length) {
|
||||
var thisSee = this.see;
|
||||
sees.map(function($){thisSee.push($.desc);});
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@see The other thing.*"+"/"));
|
||||
is(sym.see, "The other thing.", "@see tag, desc is found.");
|
||||
*/
|
||||
|
||||
// @class
|
||||
var classes = this.comment.getTag("class");
|
||||
if (classes.length) {
|
||||
this.isa = "CONSTRUCTOR";
|
||||
this.classDesc = classes[0].desc; // desc can't apply to the constructor as there is none.
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@class This describes the class.*"+"/"));
|
||||
is(sym.isa, "CONSTRUCTOR", "@class tag, makes symbol a constructor.");
|
||||
is(sym.classDesc, "This describes the class.", "@class tag, class description is found.");
|
||||
*/
|
||||
|
||||
// @namespace
|
||||
var namespaces = this.comment.getTag("namespace");
|
||||
if (namespaces.length) {
|
||||
this.classDesc = namespaces[0].desc;
|
||||
this.isNamespace = true;
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@namespace This describes the namespace.*"+"/"));
|
||||
is(sym.classDesc, "This describes the namespace.", "@namespace tag, class description is found.");
|
||||
*/
|
||||
|
||||
// @param
|
||||
var params = this.comment.getTag("param");
|
||||
if (params.length) {
|
||||
// user-defined params overwrite those with same name defined by the parser
|
||||
var thisParams = this.params;
|
||||
|
||||
if (thisParams.length == 0) { // none exist yet, so just bung all these user-defined params straight in
|
||||
this.params = params;
|
||||
}
|
||||
else { // need to overlay these user-defined params on to existing parser-defined params
|
||||
for (var i = 0, l = params.length; i < l; i++) {
|
||||
if (thisParams[i]) {
|
||||
if (params[i].type) thisParams[i].type = params[i].type;
|
||||
thisParams[i].name = params[i].name;
|
||||
thisParams[i].desc = params[i].desc;
|
||||
thisParams[i].isOptional = params[i].isOptional;
|
||||
thisParams[i].defaultValue = params[i].defaultValue;
|
||||
}
|
||||
else thisParams[i] = params[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new JSDOC.DocComment("/**Description.*"+"/"));
|
||||
is(sym.params.length, 1, "parser defined param is found.");
|
||||
|
||||
sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {array} pages*"+"/"));
|
||||
is(sym.params.length, 1, "user defined param is found.");
|
||||
is(sym.params[0].type, "array", "user defined param type is found.");
|
||||
is(sym.params[0].name, "pages", "user defined param name is found.");
|
||||
|
||||
sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {string} uid*"+"/"));
|
||||
is(sym.params.length, 1, "user defined param overwrites parser defined param.");
|
||||
is(sym.params[0].type, "string", "user defined param type overwrites parser defined param type.");
|
||||
is(sym.params[0].name, "uid", "user defined param name overwrites parser defined param name.");
|
||||
|
||||
sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}, {type: "number", name: "count"}], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {string} uid*"+"/"));
|
||||
is(sym.params.length, 2, "user defined params overlay parser defined params.");
|
||||
is(sym.params[1].type, "number", "user defined param type overlays parser defined param type.");
|
||||
is(sym.params[1].name, "count", "user defined param name overlays parser defined param name.");
|
||||
|
||||
sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {array} pages The pages description.*"+"/"));
|
||||
is(sym.params.length, 1, "user defined param with description is found.");
|
||||
is(sym.params[0].desc, "The pages description.", "user defined param description is found.");
|
||||
*/
|
||||
|
||||
// @constructor
|
||||
if (this.comment.getTag("constructor").length) {
|
||||
this.isa = "CONSTRUCTOR";
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@constructor*"+"/"));
|
||||
is(sym.isa, "CONSTRUCTOR", "@constructor tag, makes symbol a constructor.");
|
||||
*/
|
||||
|
||||
// @static
|
||||
if (this.comment.getTag("static").length) {
|
||||
this.isStatic = true;
|
||||
if (this.isa == "CONSTRUCTOR") {
|
||||
this.isNamespace = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@static\n@constructor*"+"/"));
|
||||
is(sym.isStatic, true, "@static tag, makes isStatic true.");
|
||||
is(sym.isNamespace, true, "@static and @constructor tag, makes isNamespace true.");
|
||||
*/
|
||||
|
||||
// @inner
|
||||
if (this.comment.getTag("inner").length) {
|
||||
this.isInner = true;
|
||||
this.isStatic = false;
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@inner*"+"/"));
|
||||
is(sym.isStatic, false, "@inner tag, makes isStatic false.");
|
||||
is(sym.isInner, true, "@inner makes isInner true.");
|
||||
*/
|
||||
|
||||
// @name
|
||||
var names = this.comment.getTag("name");
|
||||
if (names.length) {
|
||||
this.name = names[0].desc;
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @field
|
||||
if (this.comment.getTag("field").length) {
|
||||
this.isa = "OBJECT";
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**@field*"+"/"));
|
||||
is(sym.isa, "OBJECT", "@field tag, makes symbol an object.");
|
||||
*/
|
||||
|
||||
// @function
|
||||
if (this.comment.getTag("function").length) {
|
||||
this.isa = "FUNCTION";
|
||||
if (/event:/.test(this.alias)) this.isEvent = true;
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@function*"+"/"));
|
||||
is(sym.isa, "FUNCTION", "@function tag, makes symbol a function.");
|
||||
*/
|
||||
|
||||
// @event
|
||||
var events = this.comment.getTag("event");
|
||||
if (events.length) {
|
||||
this.isa = "FUNCTION";
|
||||
this.isEvent = true;
|
||||
if (!/event:/.test(this.alias))
|
||||
this.alias = this.alias.replace(/^(.*[.#-])([^.#-]+)$/, "$1event:$2");
|
||||
}
|
||||
|
||||
/*t:
|
||||
var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@event*"+"/"));
|
||||
is(sym.isa, "FUNCTION", "@event tag, makes symbol a function.");
|
||||
is(sym.isEvent, true, "@event makes isEvent true.");
|
||||
*/
|
||||
|
||||
// @fires
|
||||
var fires = this.comment.getTag("fires");
|
||||
if (fires.length) {
|
||||
for (var i = 0; i < fires.length; i++) {
|
||||
this.fires.push(fires[i].desc);
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @property
|
||||
var properties = this.comment.getTag("property");
|
||||
if (properties.length) {
|
||||
thisProperties = this.properties;
|
||||
for (var i = 0; i < properties.length; i++) {
|
||||
var property = new JSDOC.Symbol(this.alias+"#"+properties[i].name, [], "OBJECT", new JSDOC.DocComment("/**"+properties[i].desc+"*/"));
|
||||
// TODO: shouldn't the following happen in the addProperty method of Symbol?
|
||||
if (properties[i].type) property.type = properties[i].type;
|
||||
if (properties[i].defaultValue) property.defaultValue = properties[i].defaultValue;
|
||||
this.addProperty(property);
|
||||
if (!JSDOC.Parser.symbols.getSymbolByName(property.name))
|
||||
JSDOC.Parser.addSymbol(property);
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @return
|
||||
var returns = this.comment.getTag("return");
|
||||
if (returns.length) { // there can be many return tags in a single doclet
|
||||
this.returns = returns;
|
||||
this.type = returns.map(function($){return $.type}).join(", ");
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @exception
|
||||
this.exceptions = this.comment.getTag("throws");
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @requires
|
||||
var requires = this.comment.getTag("requires");
|
||||
if (requires.length) {
|
||||
this.requires = requires.map(function($){return $.desc});
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @type
|
||||
var types = this.comment.getTag("type");
|
||||
if (types.length) {
|
||||
this.type = types[0].desc; //multiple type tags are ignored
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @private
|
||||
if (this.comment.getTag("private").length || this.isInner) {
|
||||
this.isPrivate = true;
|
||||
}
|
||||
|
||||
// @ignore
|
||||
if (this.comment.getTag("ignore").length) {
|
||||
this.isIgnored = true;
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @inherits ... as ...
|
||||
var inherits = this.comment.getTag("inherits");
|
||||
if (inherits.length) {
|
||||
for (var i = 0; i < inherits.length; i++) {
|
||||
if (/^\s*([a-z$0-9_.#:-]+)(?:\s+as\s+([a-z$0-9_.#:-]+))?/i.test(inherits[i].desc)) {
|
||||
var inAlias = RegExp.$1;
|
||||
var inAs = RegExp.$2 || inAlias;
|
||||
|
||||
if (inAlias) inAlias = inAlias.replace(/\.prototype\.?/g, "#");
|
||||
|
||||
if (inAs) {
|
||||
inAs = inAs.replace(/\.prototype\.?/g, "#");
|
||||
inAs = inAs.replace(/^this\.?/, "#");
|
||||
}
|
||||
|
||||
if (inAs.indexOf(inAlias) != 0) { //not a full namepath
|
||||
var joiner = ".";
|
||||
if (this.alias.charAt(this.alias.length-1) == "#" || inAs.charAt(0) == "#") {
|
||||
joiner = "";
|
||||
}
|
||||
inAs = this.alias + joiner + inAs;
|
||||
}
|
||||
}
|
||||
this.inherits.push({alias: inAlias, as: inAs});
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @augments
|
||||
this.augments = this.comment.getTag("augments");
|
||||
|
||||
// @default
|
||||
var defaults = this.comment.getTag("default");
|
||||
if (defaults.length) {
|
||||
if (this.is("OBJECT")) {
|
||||
this.defaultValue = defaults[0].desc;
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @memberOf
|
||||
var memberOfs = this.comment.getTag("memberOf");
|
||||
if (memberOfs.length) {
|
||||
this.memberOf = memberOfs[0].desc;
|
||||
this.memberOf = this.memberOf.replace(/\.prototype\.?/g, "#");
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
// @public
|
||||
if (this.comment.getTag("public").length) {
|
||||
this.isPrivate = false;
|
||||
}
|
||||
|
||||
/*t:
|
||||
// todo
|
||||
*/
|
||||
|
||||
if (JSDOC.PluginManager) {
|
||||
JSDOC.PluginManager.run("onSetTags", this);
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.is = function(what) {
|
||||
return this.isa === what;
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.isBuiltin = function() {
|
||||
return JSDOC.Lang.isBuiltin(this.alias);
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.setType = function(/**String*/comment, /**Boolean*/overwrite) {
|
||||
if (!overwrite && this.type) return;
|
||||
var typeComment = JSDOC.DocComment.unwrapComment(comment);
|
||||
this.type = typeComment;
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.inherit = function(symbol) {
|
||||
if (!this.hasMember(symbol.name) && !symbol.isInner) {
|
||||
if (symbol.is("FUNCTION"))
|
||||
this.methods.push(symbol);
|
||||
else if (symbol.is("OBJECT"))
|
||||
this.properties.push(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.hasMember = function(name) {
|
||||
return (this.hasMethod(name) || this.hasProperty(name));
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.addMember = function(symbol) {
|
||||
if (symbol.is("FUNCTION")) { this.addMethod(symbol); }
|
||||
else if (symbol.is("OBJECT")) { this.addProperty(symbol); }
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.hasMethod = function(name) {
|
||||
var thisMethods = this.methods;
|
||||
for (var i = 0, l = thisMethods.length; i < l; i++) {
|
||||
if (thisMethods[i].name == name) return true;
|
||||
if (thisMethods[i].alias == name) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.addMethod = function(symbol) {
|
||||
var methodAlias = symbol.alias;
|
||||
var thisMethods = this.methods;
|
||||
for (var i = 0, l = thisMethods.length; i < l; i++) {
|
||||
if (thisMethods[i].alias == methodAlias) {
|
||||
thisMethods[i] = symbol; // overwriting previous method
|
||||
return;
|
||||
}
|
||||
}
|
||||
thisMethods.push(symbol); // new method with this alias
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.hasProperty = function(name) {
|
||||
var thisProperties = this.properties;
|
||||
for (var i = 0, l = thisProperties.length; i < l; i++) {
|
||||
if (thisProperties[i].name == name) return true;
|
||||
if (thisProperties[i].alias == name) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JSDOC.Symbol.prototype.addProperty = function(symbol) {
|
||||
var propertyAlias = symbol.alias;
|
||||
var thisProperties = this.properties;
|
||||
for (var i = 0, l = thisProperties.length; i < l; i++) {
|
||||
if (thisProperties[i].alias == propertyAlias) {
|
||||
thisProperties[i] = symbol; // overwriting previous property
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
thisProperties.push(symbol); // new property with this alias
|
||||
}
|
||||
|
||||
JSDOC.Symbol.srcFile = ""; //running reference to the current file being parsed
|
|
@ -1,242 +0,0 @@
|
|||
/** @constructor */
|
||||
JSDOC.SymbolSet = function() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.init = function() {
|
||||
this._index = new Hash();
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.keys = function() {
|
||||
return this._index.keys();
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.hasSymbol = function(alias) {
|
||||
return this._index.hasKey(alias);
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.addSymbol = function(symbol) {
|
||||
if (this.hasSymbol(symbol.alias)) {
|
||||
LOG.warn("Overwriting symbol documentation for: "+symbol.alias + ".");
|
||||
}
|
||||
this._index.set(symbol.alias, symbol);
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.getSymbol = function(alias) {
|
||||
if (this.hasSymbol(alias)) return this._index.get(alias);
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.getSymbolByName = function(name) {
|
||||
for (var p = this._index.first(); p; p = this._index.next()) {
|
||||
var symbol = p.value;
|
||||
if (symbol.name == name) return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.toArray = function() {
|
||||
return this._index.values();
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.deleteSymbol = function(alias) {
|
||||
if (!this.hasSymbol(alias)) return;
|
||||
this._index.drop(alias);
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.renameSymbol = function(oldName, newName) {
|
||||
// todo: should check if oldname or newname already exist
|
||||
this._index.replace(oldName, newName);
|
||||
this._index.get(newName).alias = newName;
|
||||
return newName;
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.relate = function() {
|
||||
this.resolveBorrows();
|
||||
this.resolveMemberOf();
|
||||
this.resolveAugments();
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.resolveBorrows = function() {
|
||||
for (var p = this._index.first(); p; p = this._index.next()) {
|
||||
var symbol = p.value;
|
||||
if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
|
||||
|
||||
var borrows = symbol.inherits;
|
||||
for (var i = 0; i < borrows.length; i++) {
|
||||
|
||||
if (/#$/.test(borrows[i].alias)) {
|
||||
LOG.warn("Attempted to borrow entire instance of "+borrows[i].alias+" but that feature is not yet implemented.");
|
||||
return;
|
||||
}
|
||||
var borrowed = this.getSymbol(borrows[i].alias);
|
||||
|
||||
if (!borrowed) {
|
||||
LOG.warn("Can't borrow undocumented "+borrows[i].alias+".");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (borrows[i].as == borrowed.alias) {
|
||||
var assumedName = borrowed.name.split(/([#.-])/).pop();
|
||||
borrows[i].as = symbol.name+RegExp.$1+assumedName;
|
||||
LOG.inform("Assuming borrowed as name is "+borrows[i].as+" but that feature is experimental.");
|
||||
}
|
||||
|
||||
var borrowAsName = borrows[i].as;
|
||||
var borrowAsAlias = borrowAsName;
|
||||
if (!borrowAsName) {
|
||||
LOG.warn("Malformed @borrow, 'as' is required.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) {
|
||||
borrowAsName = borrowAsName.replace(borrowed.alias, "")
|
||||
}
|
||||
else {
|
||||
var joiner = "";
|
||||
if (borrowAsName.charAt(0) != "#") joiner = ".";
|
||||
borrowAsAlias = borrowed.alias + joiner + borrowAsName;
|
||||
}
|
||||
|
||||
borrowAsName = borrowAsName.replace(/^[#.]/, "");
|
||||
|
||||
if (this.hasSymbol(borrowAsAlias)) continue;
|
||||
|
||||
var clone = borrowed.clone();
|
||||
clone.name = borrowAsName;
|
||||
clone.alias = borrowAsAlias;
|
||||
this.addSymbol(clone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.resolveMemberOf = function() {
|
||||
for (var p = this._index.first(); p; p = this._index.next()) {
|
||||
var symbol = p.value;
|
||||
|
||||
if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
|
||||
|
||||
// the memberOf value was provided in the @memberOf tag
|
||||
else if (symbol.memberOf) {
|
||||
// like foo.bar is a memberOf foo
|
||||
if (symbol.alias.indexOf(symbol.memberOf) == 0) {
|
||||
var memberMatch = new RegExp("^("+symbol.memberOf+")[.#-]?(.+)$");
|
||||
var aliasParts = symbol.alias.match(memberMatch);
|
||||
|
||||
if (aliasParts) {
|
||||
symbol.memberOf = aliasParts[1];
|
||||
symbol.name = aliasParts[2];
|
||||
}
|
||||
|
||||
var nameParts = symbol.name.match(memberMatch);
|
||||
|
||||
if (nameParts) {
|
||||
symbol.name = nameParts[2];
|
||||
}
|
||||
}
|
||||
// like bar is a memberOf foo
|
||||
else {
|
||||
var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1);
|
||||
if (!/[.#-]/.test(joiner)) symbol.memberOf += ".";
|
||||
this.renameSymbol(symbol.alias, symbol.memberOf + symbol.name);
|
||||
}
|
||||
}
|
||||
// the memberOf must be calculated
|
||||
else {
|
||||
var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/);
|
||||
|
||||
if (parts) {
|
||||
symbol.memberOf = parts[1];
|
||||
symbol.name = parts[2];
|
||||
}
|
||||
}
|
||||
|
||||
// set isStatic, isInner
|
||||
if (symbol.memberOf) {
|
||||
switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) {
|
||||
case '#' :
|
||||
symbol.isStatic = false;
|
||||
symbol.isInner = false;
|
||||
break;
|
||||
case '.' :
|
||||
symbol.isStatic = true;
|
||||
symbol.isInner = false;
|
||||
break;
|
||||
case '-' :
|
||||
symbol.isStatic = false;
|
||||
symbol.isInner = true;
|
||||
break;
|
||||
default: // memberOf ends in none of the above
|
||||
symbol.isStatic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// unowned methods and fields belong to the global object
|
||||
if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") {
|
||||
symbol.memberOf = "_global_";
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (symbol.memberOf.match(/[.#-]$/)) {
|
||||
symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1);
|
||||
}
|
||||
// add to parent's methods or properties list
|
||||
if (symbol.memberOf) {
|
||||
|
||||
var container = this.getSymbol(symbol.memberOf);
|
||||
if (!container) {
|
||||
if (JSDOC.Lang.isBuiltin(symbol.memberOf)) container = JSDOC.Parser.addBuiltin(symbol.memberOf);
|
||||
else {
|
||||
LOG.warn("Trying to document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+".");
|
||||
}
|
||||
}
|
||||
|
||||
if (container) container.addMember(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.resolveAugments = function() {
|
||||
for (var p = this._index.first(); p; p = this._index.next()) {
|
||||
var symbol = p.value;
|
||||
|
||||
if (symbol.alias == "_global_" || symbol.is("FILE")) continue;
|
||||
JSDOC.SymbolSet.prototype.walk.apply(this, [symbol]);
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.SymbolSet.prototype.walk = function(symbol) {
|
||||
var augments = symbol.augments;
|
||||
for(var i = 0; i < augments.length; i++) {
|
||||
var contributer = this.getSymbol(augments[i]);
|
||||
if (!contributer && JSDOC.Lang.isBuiltin(''+augments[i])) {
|
||||
contributer = new JSDOC.Symbol("_global_."+augments[i], [], augments[i], new JSDOC.DocComment("Built in."));
|
||||
contributer.isNamespace = true;
|
||||
contributer.srcFile = "";
|
||||
contributer.isPrivate = false;
|
||||
JSDOC.Parser.addSymbol(contributer);
|
||||
}
|
||||
|
||||
if (contributer) {
|
||||
if (contributer.augments.length) {
|
||||
JSDOC.SymbolSet.prototype.walk.apply(this, [contributer]);
|
||||
}
|
||||
|
||||
symbol.inheritsFrom.push(contributer.alias);
|
||||
//if (!isUnique(symbol.inheritsFrom)) {
|
||||
// LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once.");
|
||||
//}
|
||||
//else {
|
||||
var cmethods = contributer.methods;
|
||||
var cproperties = contributer.properties;
|
||||
|
||||
for (var ci = 0, cl = cmethods.length; ci < cl; ci++) {
|
||||
if (!cmethods[ci].isStatic) symbol.inherit(cmethods[ci]);
|
||||
}
|
||||
for (var ci = 0, cl = cproperties.length; ci < cl; ci++) {
|
||||
if (!cproperties[ci].isStatic) symbol.inherit(cproperties[ci]);
|
||||
}
|
||||
//}
|
||||
}
|
||||
else LOG.warn("Can't augment contributer: "+augments[i]+", not found.");
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
|
||||
/**
|
||||
@constructor
|
||||
*/
|
||||
JSDOC.TextStream = function(text) {
|
||||
if (typeof(text) == "undefined") text = "";
|
||||
text = ""+text;
|
||||
this.text = text;
|
||||
this.cursor = 0;
|
||||
}
|
||||
|
||||
JSDOC.TextStream.prototype.look = function(n) {
|
||||
if (typeof n == "undefined") n = 0;
|
||||
|
||||
if (this.cursor+n < 0 || this.cursor+n >= this.text.length) {
|
||||
var result = new String("");
|
||||
result.eof = true;
|
||||
return result;
|
||||
}
|
||||
return this.text.charAt(this.cursor+n);
|
||||
}
|
||||
|
||||
JSDOC.TextStream.prototype.next = function(n) {
|
||||
if (typeof n == "undefined") n = 1;
|
||||
if (n < 1) return null;
|
||||
|
||||
var pulled = "";
|
||||
for (var i = 0; i < n; i++) {
|
||||
if (this.cursor+i < this.text.length) {
|
||||
pulled += this.text.charAt(this.cursor+i);
|
||||
}
|
||||
else {
|
||||
var result = new String("");
|
||||
result.eof = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
this.cursor += n;
|
||||
return pulled;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
if (typeof JSDOC == "undefined") JSDOC = {};
|
||||
|
||||
/**
|
||||
@constructor
|
||||
*/
|
||||
JSDOC.Token = function(data, type, name) {
|
||||
this.data = data;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
JSDOC.Token.prototype.toString = function() {
|
||||
return "<"+this.type+" name=\""+this.name+"\">"+this.data+"</"+this.type+">";
|
||||
}
|
||||
|
||||
JSDOC.Token.prototype.is = function(what) {
|
||||
return this.name === what || this.type === what;
|
||||
}
|
|
@ -1,332 +0,0 @@
|
|||
if (typeof JSDOC == "undefined") JSDOC = {};
|
||||
|
||||
/**
|
||||
@class Search a {@link JSDOC.TextStream} for language tokens.
|
||||
*/
|
||||
JSDOC.TokenReader = function() {
|
||||
this.keepDocs = true;
|
||||
this.keepWhite = false;
|
||||
this.keepComments = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@type {JSDOC.Token[]}
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.tokenize = function(/**JSDOC.TextStream*/stream) {
|
||||
var tokens = [];
|
||||
/**@ignore*/ tokens.last = function() { return tokens[tokens.length-1]; }
|
||||
/**@ignore*/ tokens.lastSym = function() {
|
||||
for (var i = tokens.length-1; i >= 0; i--) {
|
||||
if (!(tokens[i].is("WHIT") || tokens[i].is("COMM"))) return tokens[i];
|
||||
}
|
||||
}
|
||||
|
||||
while (!stream.look().eof) {
|
||||
if (this.read_mlcomment(stream, tokens)) continue;
|
||||
if (this.read_slcomment(stream, tokens)) continue;
|
||||
if (this.read_dbquote(stream, tokens)) continue;
|
||||
if (this.read_snquote(stream, tokens)) continue;
|
||||
if (this.read_regx(stream, tokens)) continue;
|
||||
if (this.read_numb(stream, tokens)) continue;
|
||||
if (this.read_punc(stream, tokens)) continue;
|
||||
if (this.read_newline(stream, tokens)) continue;
|
||||
if (this.read_space(stream, tokens)) continue;
|
||||
if (this.read_word(stream, tokens)) continue;
|
||||
|
||||
// if execution reaches here then an error has happened
|
||||
tokens.push(new JSDOC.Token(stream.next(), "TOKN", "UNKNOWN_TOKEN"));
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_word = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
var found = "";
|
||||
while (!stream.look().eof && JSDOC.Lang.isWordChar(stream.look())) {
|
||||
found += stream.next();
|
||||
}
|
||||
|
||||
if (found === "") {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
var name;
|
||||
if ((name = JSDOC.Lang.keyword(found))) tokens.push(new JSDOC.Token(found, "KEYW", name));
|
||||
else tokens.push(new JSDOC.Token(found, "NAME", "NAME"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_punc = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
var found = "";
|
||||
var name;
|
||||
while (!stream.look().eof && JSDOC.Lang.punc(found+stream.look())) {
|
||||
found += stream.next();
|
||||
}
|
||||
|
||||
if (found === "") {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
tokens.push(new JSDOC.Token(found, "PUNC", JSDOC.Lang.punc(found)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_space = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
var found = "";
|
||||
|
||||
while (!stream.look().eof && JSDOC.Lang.isSpace(stream.look())) {
|
||||
found += stream.next();
|
||||
}
|
||||
|
||||
if (found === "") {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (this.collapseWhite) found = " ";
|
||||
if (this.keepWhite) tokens.push(new JSDOC.Token(found, "WHIT", "SPACE"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_newline = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
var found = "";
|
||||
|
||||
while (!stream.look().eof && JSDOC.Lang.isNewline(stream.look())) {
|
||||
found += stream.next();
|
||||
}
|
||||
|
||||
if (found === "") {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (this.collapseWhite) found = "\n";
|
||||
if (this.keepWhite) tokens.push(new JSDOC.Token(found, "WHIT", "NEWLINE"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_mlcomment = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
if (stream.look() == "/" && stream.look(1) == "*") {
|
||||
var found = stream.next(2);
|
||||
|
||||
while (!stream.look().eof && !(stream.look(-1) == "/" && stream.look(-2) == "*")) {
|
||||
found += stream.next();
|
||||
}
|
||||
|
||||
// to start doclet we allow /** or /*** but not /**/ or /****
|
||||
if (/^\/\*\*([^\/]|\*[^*])/.test(found) && this.keepDocs) tokens.push(new JSDOC.Token(found, "COMM", "JSDOC"));
|
||||
else if (this.keepComments) tokens.push(new JSDOC.Token(found, "COMM", "MULTI_LINE_COMM"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_slcomment = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
var found;
|
||||
if (
|
||||
(stream.look() == "/" && stream.look(1) == "/" && (found=stream.next(2)))
|
||||
||
|
||||
(stream.look() == "<" && stream.look(1) == "!" && stream.look(2) == "-" && stream.look(3) == "-" && (found=stream.next(4)))
|
||||
) {
|
||||
|
||||
while (!stream.look().eof && !JSDOC.Lang.isNewline(stream.look())) {
|
||||
found += stream.next();
|
||||
}
|
||||
|
||||
if (this.keepComments) {
|
||||
tokens.push(new JSDOC.Token(found, "COMM", "SINGLE_LINE_COMM"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_dbquote = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
if (stream.look() == "\"") {
|
||||
// find terminator
|
||||
var string = stream.next();
|
||||
|
||||
while (!stream.look().eof) {
|
||||
if (stream.look() == "\\") {
|
||||
if (JSDOC.Lang.isNewline(stream.look(1))) {
|
||||
do {
|
||||
stream.next();
|
||||
} while (!stream.look().eof && JSDOC.Lang.isNewline(stream.look()));
|
||||
string += "\\\n";
|
||||
}
|
||||
else {
|
||||
string += stream.next(2);
|
||||
}
|
||||
}
|
||||
else if (stream.look() == "\"") {
|
||||
string += stream.next();
|
||||
tokens.push(new JSDOC.Token(string, "STRN", "DOUBLE_QUOTE"));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
string += stream.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false; // error! unterminated string
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_snquote = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
if (stream.look() == "'") {
|
||||
// find terminator
|
||||
var string = stream.next();
|
||||
|
||||
while (!stream.look().eof) {
|
||||
if (stream.look() == "\\") { // escape sequence
|
||||
string += stream.next(2);
|
||||
}
|
||||
else if (stream.look() == "'") {
|
||||
string += stream.next();
|
||||
tokens.push(new JSDOC.Token(string, "STRN", "SINGLE_QUOTE"));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
string += stream.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false; // error! unterminated string
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_numb = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
if (stream.look() === "0" && stream.look(1) == "x") {
|
||||
return this.read_hex(stream, tokens);
|
||||
}
|
||||
|
||||
var found = "";
|
||||
|
||||
while (!stream.look().eof && JSDOC.Lang.isNumber(found+stream.look())){
|
||||
found += stream.next();
|
||||
}
|
||||
|
||||
if (found === "") {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (/^0[0-7]/.test(found)) tokens.push(new JSDOC.Token(found, "NUMB", "OCTAL"));
|
||||
else tokens.push(new JSDOC.Token(found, "NUMB", "DECIMAL"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/*t:
|
||||
requires("../lib/JSDOC/TextStream.js");
|
||||
requires("../lib/JSDOC/Token.js");
|
||||
requires("../lib/JSDOC/Lang.js");
|
||||
|
||||
plan(3, "testing JSDOC.TokenReader.prototype.read_numb");
|
||||
|
||||
//// setup
|
||||
var src = "function foo(num){while (num+8.0 >= 0x20 && num < 0777){}}";
|
||||
var tr = new JSDOC.TokenReader();
|
||||
var tokens = tr.tokenize(new JSDOC.TextStream(src));
|
||||
|
||||
var hexToken, octToken, decToken;
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
if (tokens[i].name == "HEX_DEC") hexToken = tokens[i];
|
||||
if (tokens[i].name == "OCTAL") octToken = tokens[i];
|
||||
if (tokens[i].name == "DECIMAL") decToken = tokens[i];
|
||||
}
|
||||
////
|
||||
|
||||
is(decToken.data, "8.0", "decimal number is found in source.");
|
||||
is(hexToken.data, "0x20", "hexdec number is found in source (issue #99).");
|
||||
is(octToken.data, "0777", "octal number is found in source.");
|
||||
*/
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_hex = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
var found = stream.next(2);
|
||||
|
||||
while (!stream.look().eof) {
|
||||
if (JSDOC.Lang.isHexDec(found) && !JSDOC.Lang.isHexDec(found+stream.look())) { // done
|
||||
tokens.push(new JSDOC.Token(found, "NUMB", "HEX_DEC"));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
found += stream.next();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {Boolean} Was the token found?
|
||||
*/
|
||||
JSDOC.TokenReader.prototype.read_regx = function(/**JSDOC.TokenStream*/stream, tokens) {
|
||||
var last;
|
||||
if (
|
||||
stream.look() == "/"
|
||||
&&
|
||||
(
|
||||
|
||||
(
|
||||
!(last = tokens.lastSym()) // there is no last, the regex is the first symbol
|
||||
||
|
||||
(
|
||||
!last.is("NUMB")
|
||||
&& !last.is("NAME")
|
||||
&& !last.is("RIGHT_PAREN")
|
||||
&& !last.is("RIGHT_BRACKET")
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
||||
var regex = stream.next();
|
||||
|
||||
while (!stream.look().eof) {
|
||||
if (stream.look() == "\\") { // escape sequence
|
||||
regex += stream.next(2);
|
||||
}
|
||||
else if (stream.look() == "/") {
|
||||
regex += stream.next();
|
||||
|
||||
while (/[gmi]/.test(stream.look())) {
|
||||
regex += stream.next();
|
||||
}
|
||||
|
||||
tokens.push(new JSDOC.Token(regex, "REGX", "REGX"));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
regex += stream.next();
|
||||
}
|
||||
}
|
||||
// error: unterminated regex
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
if (typeof JSDOC == "undefined") JSDOC = {};
|
||||
|
||||
/**
|
||||
@constructor
|
||||
*/
|
||||
JSDOC.TokenStream = function(tokens) {
|
||||
this.tokens = (tokens || []);
|
||||
this.rewind();
|
||||
}
|
||||
|
||||
/**
|
||||
@constructor
|
||||
@private
|
||||
*/
|
||||
function VoidToken(/**String*/type) {
|
||||
this.toString = function() {return "<VOID type=\""+type+"\">"};
|
||||
this.is = function(){return false;}
|
||||
}
|
||||
|
||||
JSDOC.TokenStream.prototype.rewind = function() {
|
||||
this.cursor = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@type JSDOC.Token
|
||||
*/
|
||||
JSDOC.TokenStream.prototype.look = function(/**Number*/n, /**Boolean*/considerWhitespace) {
|
||||
if (typeof n == "undefined") n = 0;
|
||||
|
||||
if (considerWhitespace == true) {
|
||||
if (this.cursor+n < 0 || this.cursor+n > this.tokens.length) return {};
|
||||
return this.tokens[this.cursor+n];
|
||||
}
|
||||
else {
|
||||
var count = 0;
|
||||
var i = this.cursor;
|
||||
|
||||
while (true) {
|
||||
if (i < 0) return new JSDOC.Token("", "VOID", "START_OF_STREAM");
|
||||
else if (i > this.tokens.length) return new JSDOC.Token("", "VOID", "END_OF_STREAM");
|
||||
|
||||
if (i != this.cursor && (this.tokens[i] === undefined || this.tokens[i].is("WHIT"))) {
|
||||
if (n < 0) i--; else i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count == Math.abs(n)) {
|
||||
return this.tokens[i];
|
||||
}
|
||||
count++;
|
||||
(n < 0)? i-- : i++;
|
||||
}
|
||||
|
||||
return new JSDOC.Token("", "VOID", "STREAM_ERROR"); // because null isn't an object and caller always expects an object
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@type JSDOC.Token|JSDOC.Token[]
|
||||
*/
|
||||
JSDOC.TokenStream.prototype.next = function(/**Number*/howMany) {
|
||||
if (typeof howMany == "undefined") howMany = 1;
|
||||
if (howMany < 1) return null;
|
||||
var got = [];
|
||||
|
||||
for (var i = 1; i <= howMany; i++) {
|
||||
if (this.cursor+i >= this.tokens.length) {
|
||||
return null;
|
||||
}
|
||||
got.push(this.tokens[this.cursor+i]);
|
||||
}
|
||||
this.cursor += howMany;
|
||||
|
||||
if (howMany == 1) {
|
||||
return got[0];
|
||||
}
|
||||
else return got;
|
||||
}
|
||||
|
||||
/**
|
||||
@type JSDOC.Token[]
|
||||
*/
|
||||
JSDOC.TokenStream.prototype.balance = function(/**String*/start, /**String*/stop) {
|
||||
if (!stop) stop = JSDOC.Lang.matching(start);
|
||||
|
||||
var depth = 0;
|
||||
var got = [];
|
||||
var started = false;
|
||||
|
||||
while ((token = this.look())) {
|
||||
if (token.is(start)) {
|
||||
depth++;
|
||||
started = true;
|
||||
}
|
||||
|
||||
if (started) {
|
||||
got.push(token);
|
||||
}
|
||||
|
||||
if (token.is(stop)) {
|
||||
depth--;
|
||||
if (depth == 0) return got;
|
||||
}
|
||||
if (!this.next()) break;
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.TokenStream.prototype.getMatchingToken = function(/**String*/start, /**String*/stop) {
|
||||
var depth = 0;
|
||||
var cursor = this.cursor;
|
||||
|
||||
if (!start) {
|
||||
start = JSDOC.Lang.matching(stop);
|
||||
depth = 1;
|
||||
}
|
||||
if (!stop) stop = JSDOC.Lang.matching(start);
|
||||
|
||||
while ((token = this.tokens[cursor])) {
|
||||
if (token.is(start)) {
|
||||
depth++;
|
||||
}
|
||||
|
||||
if (token.is(stop) && cursor) {
|
||||
depth--;
|
||||
if (depth == 0) return this.tokens[cursor];
|
||||
}
|
||||
cursor++;
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.TokenStream.prototype.insertAhead = function(/**JSDOC.Token*/token) {
|
||||
this.tokens.splice(this.cursor+1, 0, token);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/**
|
||||
* @namespace
|
||||
* @deprecated Use {@link FilePath} instead.
|
||||
*/
|
||||
JSDOC.Util = {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link FilePath.fileName} instead.
|
||||
*/
|
||||
JSDOC.Util.fileName = function(path) {
|
||||
LOG.warn("JSDOC.Util.fileName is deprecated. Use FilePath.fileName instead.");
|
||||
var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0);
|
||||
return path.substring(nameStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link FilePath.fileExtension} instead.
|
||||
*/
|
||||
JSDOC.Util.fileExtension = function(filename) {
|
||||
LOG.warn("JSDOC.Util.fileExtension is deprecated. Use FilePath.fileExtension instead.");
|
||||
return filename.split(".").pop().toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link FilePath.dir} instead.
|
||||
*/
|
||||
JSDOC.Util.dir = function(path) {
|
||||
LOG.warn("JSDOC.Util.dir is deprecated. Use FilePath.dir instead.");
|
||||
var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0);
|
||||
return path.substring(0, nameStart-1);
|
||||
}
|
|
@ -1,507 +0,0 @@
|
|||
if (typeof JSDOC == "undefined") JSDOC = {};
|
||||
|
||||
/** @constructor */
|
||||
JSDOC.Walker = function(/**JSDOC.TokenStream*/ts) {
|
||||
this.init();
|
||||
if (typeof ts != "undefined") {
|
||||
this.walk(ts);
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.Walker.prototype.init = function() {
|
||||
this.ts = null;
|
||||
|
||||
var globalSymbol = new JSDOC.Symbol("_global_", [], "GLOBAL", new JSDOC.DocComment(""));
|
||||
globalSymbol.isNamespace = true;
|
||||
globalSymbol.srcFile = "";
|
||||
globalSymbol.isPrivate = false;
|
||||
JSDOC.Parser.addSymbol(globalSymbol);
|
||||
this.lastDoc = null;
|
||||
this.token = null;
|
||||
|
||||
/**
|
||||
The chain of symbols under which we are currently nested.
|
||||
@type Array
|
||||
*/
|
||||
this.namescope = [globalSymbol];
|
||||
this.namescope.last = function(n){ if (!n) n = 0; return this[this.length-(1+n)] || "" };
|
||||
}
|
||||
|
||||
JSDOC.Walker.prototype.walk = function(/**JSDOC.TokenStream*/ts) {
|
||||
this.ts = ts;
|
||||
while (this.token = this.ts.look()) {
|
||||
if (this.token.popNamescope) {
|
||||
|
||||
var symbol = this.namescope.pop();
|
||||
if (symbol.is("FUNCTION")) {
|
||||
if (this.ts.look(1).is("LEFT_PAREN") && symbol.comment.getTag("function").length == 0) {
|
||||
symbol.isa = "OBJECT";
|
||||
}
|
||||
}
|
||||
}
|
||||
this.step();
|
||||
if (!this.ts.next()) break;
|
||||
}
|
||||
}
|
||||
|
||||
JSDOC.Walker.prototype.step = function() {
|
||||
if (this.token.is("JSDOC")) { // it's a doc comment
|
||||
|
||||
var doc = new JSDOC.DocComment(this.token.data);
|
||||
|
||||
|
||||
if (doc.getTag("exports").length > 0) {
|
||||
var exports = doc.getTag("exports")[0];
|
||||
|
||||
exports.desc.match(/(\S+) as (\S+)/i);
|
||||
var n1 = RegExp.$1;
|
||||
var n2 = RegExp.$2;
|
||||
|
||||
if (!n1 && n2) throw "@exports tag requires a value like: 'name as ns.name'";
|
||||
|
||||
JSDOC.Parser.rename = (JSDOC.Parser.rename || {});
|
||||
JSDOC.Parser.rename[n1] = n2
|
||||
}
|
||||
|
||||
if (doc.getTag("lends").length > 0) {
|
||||
var lends = doc.getTag("lends")[0];
|
||||
|
||||
var name = lends.desc
|
||||
if (!name) throw "@lends tag requires a value.";
|
||||
|
||||
var symbol = new JSDOC.Symbol(name, [], "OBJECT", doc);
|
||||
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken("LEFT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
|
||||
this.lastDoc = null;
|
||||
return true;
|
||||
}
|
||||
else if (doc.getTag("name").length > 0 && doc.getTag("overview").length == 0) { // it's a virtual symbol
|
||||
var virtualName = doc.getTag("name")[0].desc;
|
||||
if (!virtualName) throw "@name tag requires a value.";
|
||||
|
||||
if (doc.getTag("memberOf").length > 0) {
|
||||
virtualName = (doc.getTag("memberOf")[0] + "." + virtualName)
|
||||
.replace(/([#.])\./, "$1");
|
||||
doc.deleteTag("memberOf");
|
||||
}
|
||||
|
||||
var symbol = new JSDOC.Symbol(virtualName, [], "VIRTUAL", doc);
|
||||
|
||||
JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.lastDoc = null;
|
||||
return true;
|
||||
}
|
||||
else if (doc.meta) { // it's a meta doclet
|
||||
if (doc.meta == "@+") JSDOC.DocComment.shared = doc.src;
|
||||
else if (doc.meta == "@-") JSDOC.DocComment.shared = "";
|
||||
else if (doc.meta == "nocode+") JSDOC.Parser.conf.ignoreCode = true;
|
||||
else if (doc.meta == "nocode-") JSDOC.Parser.conf.ignoreCode = JSDOC.opt.n;
|
||||
else throw "Unrecognized meta comment: "+doc.meta;
|
||||
|
||||
this.lastDoc = null;
|
||||
return true;
|
||||
}
|
||||
else if (doc.getTag("overview").length > 0) { // it's a file overview
|
||||
symbol = new JSDOC.Symbol("", [], "FILE", doc);
|
||||
|
||||
JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.lastDoc = null;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
this.lastDoc = doc;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!JSDOC.Parser.conf.ignoreCode) { // it's code
|
||||
if (this.token.is("NAME")) { // it's the name of something
|
||||
var symbol;
|
||||
var name = this.token.data;
|
||||
var doc = null; if (this.lastDoc) doc = this.lastDoc;
|
||||
var params = [];
|
||||
|
||||
// it's inside an anonymous object
|
||||
if (this.ts.look(1).is("COLON") && this.ts.look(-1).is("LEFT_CURLY") && !(this.ts.look(-2).is("JSDOC") || this.namescope.last().comment.getTag("lends").length || this.ts.look(-2).is("ASSIGN") || this.ts.look(-2).is("COLON"))) {
|
||||
name = "$anonymous";
|
||||
name = this.namescope.last().alias+"-"+name
|
||||
|
||||
params = [];
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "OBJECT", doc);
|
||||
|
||||
JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken(null, "RIGHT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
}
|
||||
// function foo() {}
|
||||
else if (this.ts.look(-1).is("FUNCTION") && this.ts.look(1).is("LEFT_PAREN")) {
|
||||
var isInner;
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
|
||||
if (doc && doc.getTag("memberOf").length > 0) {
|
||||
name = (doc.getTag("memberOf")[0]+"."+name).replace("#.", "#");
|
||||
doc.deleteTag("memberOf");
|
||||
}
|
||||
else {
|
||||
name = this.namescope.last().alias+"-"+name;
|
||||
if (!this.namescope.last().is("GLOBAL")) isInner = true;
|
||||
}
|
||||
|
||||
if (!this.namescope.last().is("GLOBAL")) isInner = true;
|
||||
|
||||
params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN"));
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc);
|
||||
if (isInner) symbol.isInner = true;
|
||||
|
||||
if (this.ts.look(1).is("JSDOC")) {
|
||||
var inlineReturn = ""+this.ts.look(1).data;
|
||||
inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, "");
|
||||
symbol.type = inlineReturn;
|
||||
}
|
||||
|
||||
JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken("LEFT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
}
|
||||
// foo = function() {}
|
||||
else if (this.ts.look(1).is("ASSIGN") && this.ts.look(2).is("FUNCTION")) {
|
||||
var constructs;
|
||||
var isConstructor = false;
|
||||
if (doc && (constructs = doc.getTag("constructs")) && constructs.length) {
|
||||
if (constructs[0].desc) {
|
||||
name = constructs[0].desc;
|
||||
isConstructor = true;
|
||||
}
|
||||
}
|
||||
|
||||
var isInner;
|
||||
if (this.ts.look(-1).is("VAR") || this.isInner) {
|
||||
if (doc && doc.getTag("memberOf").length > 0) {
|
||||
name = (doc.getTag("memberOf")[0]+"."+name).replace("#.", "#");
|
||||
doc.deleteTag("memberOf");
|
||||
}
|
||||
else {
|
||||
name = this.namescope.last().alias+"-"+name;
|
||||
if (!this.namescope.last().is("GLOBAL")) isInner = true;
|
||||
}
|
||||
if (!this.namescope.last().is("GLOBAL")) isInner = true;
|
||||
}
|
||||
else if (name.indexOf("this.") == 0) {
|
||||
name = this.resolveThis(name);
|
||||
}
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN"));
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc);
|
||||
|
||||
if (isInner) symbol.isInner = true;
|
||||
if (isConstructor) symbol.isa = "CONSTRUCTOR";
|
||||
|
||||
if (this.ts.look(1).is("JSDOC")) {
|
||||
var inlineReturn = ""+this.ts.look(1).data;
|
||||
inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, "");
|
||||
symbol.type = inlineReturn;
|
||||
}
|
||||
|
||||
JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken("LEFT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
}
|
||||
// foo = new function() {} or foo = (function() {}
|
||||
else if (this.ts.look(1).is("ASSIGN") && (this.ts.look(2).is("NEW") || this.ts.look(2).is("LEFT_PAREN")) && this.ts.look(3).is("FUNCTION")) {
|
||||
var isInner;
|
||||
if (this.ts.look(-1).is("VAR") || this.isInner) {
|
||||
name = this.namescope.last().alias+"-"+name
|
||||
if (!this.namescope.last().is("GLOBAL")) isInner = true;
|
||||
}
|
||||
else if (name.indexOf("this.") == 0) {
|
||||
name = this.resolveThis(name);
|
||||
}
|
||||
|
||||
this.ts.next(3); // advance past the "new" or "("
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN"));
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "OBJECT", doc);
|
||||
if (isInner) symbol.isInner = true;
|
||||
|
||||
if (this.ts.look(1).is("JSDOC")) {
|
||||
var inlineReturn = ""+this.ts.look(1).data;
|
||||
inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, "");
|
||||
symbol.type = inlineReturn;
|
||||
}
|
||||
|
||||
JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
symbol.scopeType = "INSTANCE";
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken("LEFT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
}
|
||||
// foo: function() {}
|
||||
else if (this.ts.look(1).is("COLON") && this.ts.look(2).is("FUNCTION")) {
|
||||
name = (this.namescope.last().alias+"."+name).replace("#.", "#");
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN"));
|
||||
|
||||
if (doc && doc.getTag("constructs").length) {
|
||||
name = name.replace(/\.prototype(\.|$)/, "#");
|
||||
|
||||
if (name.indexOf("#") > -1) name = name.match(/(^[^#]+)/)[0];
|
||||
else name = this.namescope.last().alias;
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "CONSTRUCTOR", doc);
|
||||
}
|
||||
else {
|
||||
symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc);
|
||||
}
|
||||
|
||||
if (this.ts.look(1).is("JSDOC")) {
|
||||
var inlineReturn = ""+this.ts.look(1).data;
|
||||
inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, "");
|
||||
symbol.type = inlineReturn;
|
||||
}
|
||||
|
||||
JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken("LEFT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
}
|
||||
// foo = {}
|
||||
else if (this.ts.look(1).is("ASSIGN") && this.ts.look(2).is("LEFT_CURLY")) {
|
||||
var isInner;
|
||||
if (this.ts.look(-1).is("VAR") || this.isInner) {
|
||||
name = this.namescope.last().alias+"-"+name
|
||||
if (!this.namescope.last().is("GLOBAL")) isInner = true;
|
||||
}
|
||||
else if (name.indexOf("this.") == 0) {
|
||||
name = this.resolveThis(name);
|
||||
}
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "OBJECT", doc);
|
||||
if (isInner) symbol.isInner = true;
|
||||
|
||||
|
||||
if (doc) JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken("LEFT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
}
|
||||
// var foo;
|
||||
else if (this.ts.look(1).is("SEMICOLON")) {
|
||||
var isInner;
|
||||
|
||||
if (this.ts.look(-1).is("VAR") || this.isInner) {
|
||||
name = this.namescope.last().alias+"-"+name
|
||||
if (!this.namescope.last().is("GLOBAL")) isInner = true;
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "OBJECT", doc);
|
||||
if (isInner) symbol.isInner = true;
|
||||
|
||||
|
||||
if (doc) JSDOC.Parser.addSymbol(symbol);
|
||||
}
|
||||
}
|
||||
// foo = x
|
||||
else if (this.ts.look(1).is("ASSIGN")) {
|
||||
var isInner;
|
||||
if (this.ts.look(-1).is("VAR") || this.isInner) {
|
||||
name = this.namescope.last().alias+"-"+name
|
||||
if (!this.namescope.last().is("GLOBAL")) isInner = true;
|
||||
}
|
||||
else if (name.indexOf("this.") == 0) {
|
||||
name = this.resolveThis(name);
|
||||
}
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "OBJECT", doc);
|
||||
if (isInner) symbol.isInner = true;
|
||||
|
||||
|
||||
if (doc) JSDOC.Parser.addSymbol(symbol);
|
||||
}
|
||||
// foo: {}
|
||||
else if (this.ts.look(1).is("COLON") && this.ts.look(2).is("LEFT_CURLY")) {
|
||||
name = (this.namescope.last().alias+"."+name).replace("#.", "#");
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "OBJECT", doc);
|
||||
|
||||
|
||||
if (doc) JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken("LEFT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
}
|
||||
// foo: x
|
||||
else if (this.ts.look(1).is("COLON")) {
|
||||
name = (this.namescope.last().alias+"."+name).replace("#.", "#");;
|
||||
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "OBJECT", doc);
|
||||
|
||||
|
||||
if (doc) JSDOC.Parser.addSymbol(symbol);
|
||||
}
|
||||
// foo(...)
|
||||
else if (this.ts.look(1).is("LEFT_PAREN")) {
|
||||
if (typeof JSDOC.PluginManager != "undefined") {
|
||||
var functionCall = {name: name};
|
||||
|
||||
var cursor = this.ts.cursor;
|
||||
params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN"));
|
||||
this.ts.cursor = cursor;
|
||||
|
||||
for (var i = 0; i < params.length; i++)
|
||||
functionCall["arg" + (i + 1)] = params[i].name;
|
||||
|
||||
JSDOC.PluginManager.run("onFunctionCall", functionCall);
|
||||
if (functionCall.doc) {
|
||||
this.ts.insertAhead(new JSDOC.Token(functionCall.doc, "COMM", "JSDOC"));
|
||||
}
|
||||
}
|
||||
}
|
||||
this.lastDoc = null;
|
||||
}
|
||||
else if (this.token.is("FUNCTION")) { // it's an anonymous function
|
||||
if (
|
||||
(!this.ts.look(-1).is("COLON") || !this.ts.look(-1).is("ASSIGN"))
|
||||
&& !this.ts.look(1).is("NAME")
|
||||
) {
|
||||
if (this.lastDoc) doc = this.lastDoc;
|
||||
|
||||
name = "$anonymous";
|
||||
name = this.namescope.last().alias+"-"+name
|
||||
|
||||
params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN"));
|
||||
|
||||
symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc);
|
||||
|
||||
JSDOC.Parser.addSymbol(symbol);
|
||||
|
||||
this.namescope.push(symbol);
|
||||
|
||||
var matching = this.ts.getMatchingToken("LEFT_CURLY");
|
||||
if (matching) matching.popNamescope = name;
|
||||
else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Resolves what "this." means when it appears in a name.
|
||||
@param name The name that starts with "this.".
|
||||
@returns The name with "this." resolved.
|
||||
*/
|
||||
JSDOC.Walker.prototype.resolveThis = function(name) {
|
||||
name.match(/^this\.(.+)$/)
|
||||
var nameFragment = RegExp.$1;
|
||||
if (!nameFragment) return name;
|
||||
|
||||
var symbol = this.namescope.last();
|
||||
var scopeType = symbol.scopeType || symbol.isa;
|
||||
|
||||
// if we are in a constructor function, `this` means the instance
|
||||
if (scopeType == "CONSTRUCTOR") {
|
||||
name = symbol.alias+"#"+nameFragment;
|
||||
}
|
||||
|
||||
// if we are in an anonymous constructor function, `this` means the instance
|
||||
else if (scopeType == "INSTANCE") {
|
||||
name = symbol.alias+"."+nameFragment;
|
||||
}
|
||||
|
||||
// if we are in a function, `this` means the container (possibly the global)
|
||||
else if (scopeType == "FUNCTION") {
|
||||
// in a method of a prototype, so `this` means the constructor
|
||||
if (symbol.alias.match(/(^.*)[#.-][^#.-]+/)) {
|
||||
var parentName = RegExp.$1;
|
||||
var parent = JSDOC.Parser.symbols.getSymbol(parentName);
|
||||
|
||||
if (!parent) {
|
||||
if (JSDOC.Lang.isBuiltin(parentName)) parent = JSDOC.Parser.addBuiltin(parentName);
|
||||
else {
|
||||
if (symbol.alias.indexOf("$anonymous") < 0) // these will be ignored eventually
|
||||
LOG.warn("Trying to document "+symbol.alias+" without first documenting "+parentName+".");
|
||||
}
|
||||
}
|
||||
if (parent) name = parentName+(parent.is("CONSTRUCTOR")?"#":".")+nameFragment;
|
||||
}
|
||||
else {
|
||||
parent = this.namescope.last(1);
|
||||
name = parent.alias+(parent.is("CONSTRUCTOR")?"#":".")+nameFragment;
|
||||
}
|
||||
}
|
||||
// otherwise it means the global
|
||||
else {
|
||||
name = nameFragment;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
JSDOC.Walker.onParamList = function(/**Array*/paramTokens) {
|
||||
if (!paramTokens) {
|
||||
LOG.warn("Malformed parameter list. Can't parse code.");
|
||||
return [];
|
||||
}
|
||||
var params = [];
|
||||
for (var i = 0, l = paramTokens.length; i < l; i++) {
|
||||
if (paramTokens[i].is("JSDOC")) {
|
||||
var paramType = paramTokens[i].data.replace(/(^\/\*\* *| *\*\/$)/g, "");
|
||||
|
||||
if (paramTokens[i+1] && paramTokens[i+1].is("NAME")) {
|
||||
i++;
|
||||
params.push({type: paramType, name: paramTokens[i].data});
|
||||
}
|
||||
}
|
||||
else if (paramTokens[i].is("NAME")) {
|
||||
params.push({name: paramTokens[i].data});
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
/**
|
||||
* @version $Id: main.js 818 2009-11-08 14:51:41Z micmath $
|
||||
*/
|
||||
|
||||
function main() {
|
||||
IO.include("lib/JSDOC.js");
|
||||
IO.includeDir("plugins/");
|
||||
|
||||
// process the options
|
||||
|
||||
// the -c option: options are defined in a configuration file
|
||||
if (JSDOC.opt.c) {
|
||||
eval("JSDOC.conf = " + IO.readFile(JSDOC.opt.c));
|
||||
|
||||
LOG.inform("Using configuration file at '"+JSDOC.opt.c+"'.");
|
||||
|
||||
for (var c in JSDOC.conf) {
|
||||
if (c !== "D" && !defined(JSDOC.opt[c])) { // commandline overrules config file
|
||||
JSDOC.opt[c] = JSDOC.conf[c];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof JSDOC.conf["_"] != "undefined") {
|
||||
JSDOC.opt["_"] = JSDOC.opt["_"].concat(JSDOC.conf["_"]);
|
||||
}
|
||||
|
||||
LOG.inform("With configuration: ");
|
||||
for (var o in JSDOC.opt) {
|
||||
LOG.inform(" "+o+": "+JSDOC.opt[o]);
|
||||
}
|
||||
}
|
||||
|
||||
// be verbose
|
||||
if (JSDOC.opt.v) LOG.verbose = true;
|
||||
|
||||
// send log messages to a file
|
||||
if (JSDOC.opt.o) LOG.out = IO.open(JSDOC.opt.o);
|
||||
|
||||
// run the unit tests
|
||||
if (JSDOC.opt.T) {
|
||||
LOG.inform("JsDoc Toolkit running in test mode at "+new Date()+".");
|
||||
IO.include("frame/Testrun.js");
|
||||
IO.include("test.js");
|
||||
}
|
||||
else {
|
||||
// a template must be defined and must be a directory path
|
||||
if (!JSDOC.opt.t && System.getProperty("jsdoc.template.dir")) {
|
||||
JSDOC.opt.t = System.getProperty("jsdoc.template.dir");
|
||||
}
|
||||
if (JSDOC.opt.t && SYS.slash != JSDOC.opt.t.slice(-1)) {
|
||||
JSDOC.opt.t += SYS.slash;
|
||||
}
|
||||
|
||||
// verbose messages about the options we were given
|
||||
LOG.inform("JsDoc Toolkit main() running at "+new Date()+".");
|
||||
LOG.inform("With options: ");
|
||||
for (var o in JSDOC.opt) {
|
||||
LOG.inform(" "+o+": "+JSDOC.opt[o]);
|
||||
}
|
||||
|
||||
// initialize and build a symbolSet from your code
|
||||
JSDOC.JsDoc();
|
||||
|
||||
// debugger's option: dump the entire symbolSet produced from your code
|
||||
if (JSDOC.opt.Z) {
|
||||
LOG.warn("So you want to see the data structure, eh? This might hang if you have circular refs...");
|
||||
IO.include("frame/Dumper.js");
|
||||
var symbols = JSDOC.JsDoc.symbolSet.toArray();
|
||||
for (var i = 0, l = symbols.length; i < l; i++) {
|
||||
var symbol = symbols[i];
|
||||
print("// symbol: " + symbol.alias);
|
||||
print(symbol.serialize());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (typeof JSDOC.opt.t != "undefined") {
|
||||
try {
|
||||
// a file named "publish.js" must exist in the template directory
|
||||
load(JSDOC.opt.t+"publish.js");
|
||||
|
||||
// and must define a function named "publish"
|
||||
if (!publish) {
|
||||
LOG.warn("No publish() function is defined in that template so nothing to do.");
|
||||
}
|
||||
else {
|
||||
// which will be called with the symbolSet produced from your code
|
||||
publish(JSDOC.JsDoc.symbolSet);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
LOG.warn("Sorry, that doesn't seem to be a valid template: "+JSDOC.opt.t+"publish.js : "+e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG.warn("No template given. Might as well read the usage notes.");
|
||||
JSDOC.usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notify of any warnings
|
||||
if (!JSDOC.opt.q && LOG.warnings.length) {
|
||||
print(LOG.warnings.length+" warning"+(LOG.warnings.length != 1? "s":"")+".");
|
||||
}
|
||||
|
||||
// stop sending log messages to a file
|
||||
if (LOG.out) {
|
||||
LOG.out.flush();
|
||||
LOG.out.close();
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
JSDOC.PluginManager.registerPlugin(
|
||||
"JSDOC.commentSrcJson",
|
||||
{
|
||||
onDocCommentSrc: function(comment) {
|
||||
var json;
|
||||
if (/^\s*@json\b/.test(comment)) {
|
||||
comment.src = new String(comment.src).replace("@json", "");
|
||||
|
||||
eval("json = "+comment.src);
|
||||
var tagged = "";
|
||||
for (var i in json) {
|
||||
var tag = json[i];
|
||||
// todo handle cases where tag is an object
|
||||
tagged += "@"+i+" "+tag+"\n";
|
||||
}
|
||||
comment.src = tagged;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,16 +0,0 @@
|
|||
JSDOC.PluginManager.registerPlugin(
|
||||
"JSDOC.frameworkPrototype",
|
||||
{
|
||||
onPrototypeClassCreate: function(classCreator) {
|
||||
var desc = "";
|
||||
if (classCreator.comment) {
|
||||
desc = classCreator.comment;
|
||||
}
|
||||
var insert = desc+"/** @name "+classCreator.name+"\n@constructor\n@scope "+classCreator.name+".prototype */"
|
||||
|
||||
insert = insert.replace(/\*\/\/\*\*/g, "\n");
|
||||
/*DEBUG*///print("insert is "+insert);
|
||||
classCreator.addComment.data = insert;
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,10 +0,0 @@
|
|||
JSDOC.PluginManager.registerPlugin(
|
||||
"JSDOC.functionCall",
|
||||
{
|
||||
onFunctionCall: function(functionCall) {
|
||||
if (functionCall.name == "dojo.define" && functionCall.arg1) {
|
||||
functionCall.doc = "/** @lends "+eval(functionCall.arg1)+".prototype */";
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,62 +0,0 @@
|
|||
JSDOC.PluginManager.registerPlugin(
|
||||
"JSDOC.publishSrcHilite",
|
||||
{
|
||||
onPublishSrc: function(src) {
|
||||
if (src.path in JsHilite.cache) {
|
||||
return; // already generated src code
|
||||
}
|
||||
else JsHilite.cache[src.path] = true;
|
||||
|
||||
try {
|
||||
var sourceCode = IO.readFile(src.path);
|
||||
}
|
||||
catch(e) {
|
||||
print(e.message);
|
||||
quit();
|
||||
}
|
||||
|
||||
var hiliter = new JsHilite(sourceCode, src.charset);
|
||||
src.hilited = hiliter.hilite();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function JsHilite(src, charset) {
|
||||
|
||||
var tr = new JSDOC.TokenReader();
|
||||
|
||||
tr.keepComments = true;
|
||||
tr.keepDocs = true;
|
||||
tr.keepWhite = true;
|
||||
|
||||
this.tokens = tr.tokenize(new JSDOC.TextStream(src));
|
||||
|
||||
// TODO is redefining toString() the best way?
|
||||
JSDOC.Token.prototype.toString = function() {
|
||||
return "<span class=\""+this.type+"\">"+this.data.replace(/</g, "<")+"</span>";
|
||||
}
|
||||
|
||||
if (!charset) charset = "utf-8";
|
||||
|
||||
this.header = '<html><head><meta http-equiv="content-type" content="text/html; charset='+charset+'"> '+
|
||||
"<style>\n\
|
||||
.KEYW {color: #933;}\n\
|
||||
.COMM {color: #bbb; font-style: italic;}\n\
|
||||
.NUMB {color: #393;}\n\
|
||||
.STRN {color: #393;}\n\
|
||||
.REGX {color: #339;}\n\
|
||||
.line {border-right: 1px dotted #666; color: #666; font-style: normal;}\n\
|
||||
</style></head><body><pre>";
|
||||
this.footer = "</pre></body></html>";
|
||||
this.showLinenumbers = true;
|
||||
}
|
||||
|
||||
JsHilite.cache = {};
|
||||
|
||||
JsHilite.prototype.hilite = function() {
|
||||
var hilited = this.tokens.join("");
|
||||
var line = 1;
|
||||
if (this.showLinenumbers) hilited = hilited.replace(/(^|\n)/g, function(m){return m+"<span class='line'>"+((line<10)? " ":"")+((line<100)? " ":"")+(line++)+"</span> "});
|
||||
|
||||
return this.header+hilited+this.footer;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
JSDOC.PluginManager.registerPlugin(
|
||||
"JSDOC.symbolLink",
|
||||
{
|
||||
onSymbolLink: function(link) {
|
||||
// modify link.linkPath (the href part of the link)
|
||||
// or link.linkText (the text displayed)
|
||||
// or link.linkInner (the #name part of the link)
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,31 +0,0 @@
|
|||
JSDOC.PluginManager.registerPlugin(
|
||||
"JSDOC.tagParamConfig",
|
||||
{
|
||||
onDocCommentTags: function(comment) {
|
||||
var currentParam = null;
|
||||
var tags = comment.tags;
|
||||
for (var i = 0, l = tags.length; i < l; i++) {
|
||||
|
||||
if (tags[i].title == "param") {
|
||||
if (tags[i].name.indexOf(".") == -1) {
|
||||
currentParam = i;
|
||||
}
|
||||
}
|
||||
else if (tags[i].title == "config") {
|
||||
tags[i].title = "param";
|
||||
if (currentParam == null) {
|
||||
tags[i].name = "arguments"+"."+tags[i].name;
|
||||
}
|
||||
else if (tags[i].name.indexOf(tags[currentParam].name+".") != 0) {
|
||||
tags[i].name = tags[currentParam].name+"."+tags[i].name;
|
||||
}
|
||||
currentParam != null
|
||||
//tags[currentParam].properties.push(tags[i]);
|
||||
}
|
||||
else {
|
||||
currentParam = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,43 +0,0 @@
|
|||
JSDOC.PluginManager.registerPlugin(
|
||||
"JSDOC.tagSynonyms",
|
||||
{
|
||||
onDocCommentSrc: function(comment) {
|
||||
comment.src = comment.src.replace(/@methodOf\b/i, "@function\n@memberOf");
|
||||
comment.src = comment.src.replace(/@fieldOf\b/i, "@field\n@memberOf");
|
||||
},
|
||||
|
||||
onDocCommentTags: function(comment) {
|
||||
for (var i = 0, l = comment.tags.length; i < l; i++) {
|
||||
var title = comment.tags[i].title.toLowerCase();
|
||||
var syn;
|
||||
if ((syn = JSDOC.tagSynonyms.synonyms["="+title])) {
|
||||
comment.tags[i].title = syn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
new Namespace(
|
||||
"JSDOC.tagSynonyms",
|
||||
function() {
|
||||
JSDOC.tagSynonyms.synonyms = {
|
||||
"=member": "memberOf",
|
||||
"=memberof": "memberOf",
|
||||
"=description": "desc",
|
||||
"=exception": "throws",
|
||||
"=argument": "param",
|
||||
"=returns": "return",
|
||||
"=classdescription": "class",
|
||||
"=fileoverview": "overview",
|
||||
"=extends": "augments",
|
||||
"=base": "augments",
|
||||
"=projectdescription": "overview",
|
||||
"=classdescription": "class",
|
||||
"=link": "see",
|
||||
"=borrows": "inherits",
|
||||
"=scope": "lends",
|
||||
"=construct": "constructor"
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,348 +0,0 @@
|
|||
/**
|
||||
* @fileOverview
|
||||
* A bootstrap script that creates some basic required objects
|
||||
* for loading other scripts.
|
||||
* @author Michael Mathews, micmath@gmail.com
|
||||
* @version $Id: run.js 756 2009-01-07 21:32:58Z micmath $
|
||||
*/
|
||||
|
||||
/**
|
||||
* @namespace Keep track of any messages from the running script.
|
||||
*/
|
||||
LOG = {
|
||||
warn: function(msg, e) {
|
||||
if (JSDOC.opt.q) return;
|
||||
if (e) msg = e.fileName+", line "+e.lineNumber+": "+msg;
|
||||
|
||||
msg = ">> WARNING: "+msg;
|
||||
LOG.warnings.push(msg);
|
||||
if (LOG.out) LOG.out.write(msg+"\n");
|
||||
else print(msg);
|
||||
},
|
||||
|
||||
inform: function(msg) {
|
||||
if (JSDOC.opt.q) return;
|
||||
msg = " > "+msg;
|
||||
if (LOG.out) LOG.out.write(msg+"\n");
|
||||
else if (typeof LOG.verbose != "undefined" && LOG.verbose) print(msg);
|
||||
}
|
||||
};
|
||||
LOG.warnings = [];
|
||||
LOG.verbose = false
|
||||
LOG.out = undefined;
|
||||
|
||||
/**
|
||||
* @class Manipulate a filepath.
|
||||
*/
|
||||
function FilePath(absPath, separator) {
|
||||
this.slash = separator || "/";
|
||||
this.root = this.slash;
|
||||
this.path = [];
|
||||
this.file = "";
|
||||
|
||||
var parts = absPath.split(/[\\\/]/);
|
||||
if (parts) {
|
||||
if (parts.length) this.root = parts.shift() + this.slash;
|
||||
if (parts.length) this.file = parts.pop()
|
||||
if (parts.length) this.path = parts;
|
||||
}
|
||||
|
||||
this.path = this.resolvePath();
|
||||
}
|
||||
|
||||
/** Collapse any dot-dot or dot items in a filepath. */
|
||||
FilePath.prototype.resolvePath = function() {
|
||||
var resolvedPath = [];
|
||||
for (var i = 0; i < this.path.length; i++) {
|
||||
if (this.path[i] == "..") resolvedPath.pop();
|
||||
else if (this.path[i] != ".") resolvedPath.push(this.path[i]);
|
||||
}
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
/** Trim off the filename. */
|
||||
FilePath.prototype.toDir = function() {
|
||||
if (this.file) this.file = "";
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Go up a directory. */
|
||||
FilePath.prototype.upDir = function() {
|
||||
this.toDir();
|
||||
if (this.path.length) this.path.pop();
|
||||
return this;
|
||||
}
|
||||
|
||||
FilePath.prototype.toString = function() {
|
||||
return this.root
|
||||
+ this.path.join(this.slash)
|
||||
+ ((this.path.length > 0)? this.slash : "")
|
||||
+ this.file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a path into just the name of the file.
|
||||
*/
|
||||
FilePath.fileName = function(path) {
|
||||
var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0);
|
||||
return path.substring(nameStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extension of a filename
|
||||
*/
|
||||
FilePath.fileExtension = function(filename) {
|
||||
return filename.split(".").pop().toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* Turn a path into just the directory part.
|
||||
*/
|
||||
FilePath.dir = function(path) {
|
||||
var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0);
|
||||
return path.substring(0, nameStart-1);
|
||||
}
|
||||
|
||||
|
||||
importClass(java.lang.System);
|
||||
|
||||
/**
|
||||
* @namespace A collection of information about your system.
|
||||
*/
|
||||
SYS = {
|
||||
/**
|
||||
* Information about your operating system: arch, name, version.
|
||||
* @type string
|
||||
*/
|
||||
os: [
|
||||
new String(System.getProperty("os.arch")),
|
||||
new String(System.getProperty("os.name")),
|
||||
new String(System.getProperty("os.version"))
|
||||
].join(", "),
|
||||
|
||||
/**
|
||||
* Which way does your slash lean.
|
||||
* @type string
|
||||
*/
|
||||
slash: System.getProperty("file.separator")||"/",
|
||||
|
||||
/**
|
||||
* The path to the working directory where you ran java.
|
||||
* @type string
|
||||
*/
|
||||
userDir: new String(System.getProperty("user.dir")),
|
||||
|
||||
/**
|
||||
* Where is Java's home folder.
|
||||
* @type string
|
||||
*/
|
||||
javaHome: new String(System.getProperty("java.home")),
|
||||
|
||||
/**
|
||||
* The absolute path to the directory containing this script.
|
||||
* @type string
|
||||
*/
|
||||
pwd: undefined
|
||||
};
|
||||
|
||||
// jsrun appends an argument, with the path to here.
|
||||
if (arguments[arguments.length-1].match(/^-j=(.+)/)) {
|
||||
if (RegExp.$1.charAt(0) == SYS.slash || RegExp.$1.charAt(1) == ":") { // absolute path to here
|
||||
SYS.pwd = new FilePath(RegExp.$1).toDir().toString();
|
||||
}
|
||||
else { // relative path to here
|
||||
SYS.pwd = new FilePath(SYS.userDir + SYS.slash + RegExp.$1).toDir().toString();
|
||||
}
|
||||
arguments.pop();
|
||||
}
|
||||
else {
|
||||
print("The run.js script requires you use jsrun.jar.");
|
||||
quit();
|
||||
}
|
||||
|
||||
// shortcut
|
||||
var File = Packages.java.io.File;
|
||||
|
||||
/**
|
||||
* @namespace A collection of functions that deal with reading a writing to disk.
|
||||
*/
|
||||
IO = {
|
||||
|
||||
/**
|
||||
* Create a new file in the given directory, with the given name and contents.
|
||||
*/
|
||||
saveFile: function(/**string*/ outDir, /**string*/ fileName, /**string*/ content) {
|
||||
var out = new Packages.java.io.PrintWriter(
|
||||
new Packages.java.io.OutputStreamWriter(
|
||||
new Packages.java.io.FileOutputStream(outDir+SYS.slash+fileName),
|
||||
IO.encoding
|
||||
)
|
||||
);
|
||||
out.write(content);
|
||||
out.flush();
|
||||
out.close();
|
||||
},
|
||||
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
readFile: function(/**string*/ path) {
|
||||
if (!IO.exists(path)) {
|
||||
throw "File doesn't exist there: "+path;
|
||||
}
|
||||
return readFile(path, IO.encoding);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param inFile
|
||||
* @param outDir
|
||||
* @param [fileName=The original filename]
|
||||
*/
|
||||
copyFile: function(/**string*/ inFile, /**string*/ outDir, /**string*/ fileName) {
|
||||
if (fileName == null) fileName = FilePath.fileName(inFile);
|
||||
|
||||
var inFile = new File(inFile);
|
||||
var outFile = new File(outDir+SYS.slash+fileName);
|
||||
|
||||
var bis = new Packages.java.io.BufferedInputStream(new Packages.java.io.FileInputStream(inFile), 4096);
|
||||
var bos = new Packages.java.io.BufferedOutputStream(new Packages.java.io.FileOutputStream(outFile), 4096);
|
||||
var theChar;
|
||||
while ((theChar = bis.read()) != -1) {
|
||||
bos.write(theChar);
|
||||
}
|
||||
bos.close();
|
||||
bis.close();
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a series of nested directories.
|
||||
*/
|
||||
mkPath: function(/**Array*/ path) {
|
||||
if (path.constructor != Array) path = path.split(/[\\\/]/);
|
||||
var make = "";
|
||||
for (var i = 0, l = path.length; i < l; i++) {
|
||||
make += path[i] + SYS.slash;
|
||||
if (! IO.exists(make)) {
|
||||
IO.makeDir(make);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a directory at the given path.
|
||||
*/
|
||||
makeDir: function(/**string*/ path) {
|
||||
(new File(path)).mkdir();
|
||||
},
|
||||
|
||||
/**
|
||||
* @type string[]
|
||||
* @param dir The starting directory to look in.
|
||||
* @param [recurse=1] How many levels deep to scan.
|
||||
* @returns An array of all the paths to files in the given dir.
|
||||
*/
|
||||
ls: function(/**string*/ dir, /**number*/ recurse, _allFiles, _path) {
|
||||
if (_path === undefined) { // initially
|
||||
var _allFiles = [];
|
||||
var _path = [dir];
|
||||
}
|
||||
if (_path.length == 0) return _allFiles;
|
||||
if (recurse === undefined) recurse = 1;
|
||||
|
||||
dir = new File(dir);
|
||||
if (!dir.directory) return [String(dir)];
|
||||
var files = dir.list();
|
||||
|
||||
for (var f = 0; f < files.length; f++) {
|
||||
var file = String(files[f]);
|
||||
if (file.match(/^\.[^\.\/\\]/)) continue; // skip dot files
|
||||
|
||||
if ((new File(_path.join(SYS.slash)+SYS.slash+file)).list()) { // it's a directory
|
||||
_path.push(file);
|
||||
if (_path.length-1 < recurse) IO.ls(_path.join(SYS.slash), recurse, _allFiles, _path);
|
||||
_path.pop();
|
||||
}
|
||||
else {
|
||||
_allFiles.push((_path.join(SYS.slash)+SYS.slash+file).replace(SYS.slash+SYS.slash, SYS.slash));
|
||||
}
|
||||
}
|
||||
|
||||
return _allFiles;
|
||||
},
|
||||
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
exists: function(/**string*/ path) {
|
||||
file = new File(path);
|
||||
|
||||
if (file.isDirectory()){
|
||||
return true;
|
||||
}
|
||||
if (!file.exists()){
|
||||
return false;
|
||||
}
|
||||
if (!file.canRead()){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
open: function(/**string*/ path, /**string*/ append) {
|
||||
var append = true;
|
||||
var outFile = new File(path);
|
||||
var out = new Packages.java.io.PrintWriter(
|
||||
new Packages.java.io.OutputStreamWriter(
|
||||
new Packages.java.io.FileOutputStream(outFile, append),
|
||||
IO.encoding
|
||||
)
|
||||
);
|
||||
return out;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets {@link IO.encoding}.
|
||||
* Encoding is used when reading and writing text to files,
|
||||
* and in the meta tags of HTML output.
|
||||
*/
|
||||
setEncoding: function(/**string*/ encoding) {
|
||||
if (/ISO-8859-([0-9]+)/i.test(encoding)) {
|
||||
IO.encoding = "ISO8859_"+RegExp.$1;
|
||||
}
|
||||
else {
|
||||
IO.encoding = encoding;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @default "utf-8"
|
||||
* @private
|
||||
*/
|
||||
encoding: "utf-8",
|
||||
|
||||
/**
|
||||
* Load the given script.
|
||||
*/
|
||||
include: function(relativePath) {
|
||||
load(SYS.pwd+relativePath);
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads all scripts from the given directory path.
|
||||
*/
|
||||
includeDir: function(path) {
|
||||
if (!path) return;
|
||||
|
||||
for (var lib = IO.ls(SYS.pwd+path), i = 0; i < lib.length; i++)
|
||||
if (/\.js$/i.test(lib[i])) load(lib[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// now run the application
|
||||
IO.include("frame.js");
|
||||
IO.include("main.js");
|
||||
|
||||
main();
|
|
@ -1,144 +0,0 @@
|
|||
var TestDoc = {
|
||||
fails: 0,
|
||||
plans: 0,
|
||||
passes: 0,
|
||||
results: []
|
||||
};
|
||||
|
||||
TestDoc.record = function(result) {
|
||||
TestDoc.results.push(result);
|
||||
if (typeof result.verdict == "boolean") {
|
||||
if (result.verdict === false) TestDoc.fails++;
|
||||
if (result.verdict === true) TestDoc.passes++;
|
||||
}
|
||||
}
|
||||
|
||||
TestDoc.prove = function(filePath) {
|
||||
if (typeof document != "undefined" && typeof document.write != "undefined") {
|
||||
if (TestDoc.console) print = function(s) { TestDoc.console.appendChild(document.createTextNode(s+"\n")); }
|
||||
else print = function(s) { document.write(s+"<br />"); }
|
||||
}
|
||||
TestDoc.run(TestDoc.readFile(filePath));
|
||||
}
|
||||
|
||||
TestDoc.run = function(src) {
|
||||
try { eval(src); } catch(e) { print("# ERROR! "+e); }
|
||||
|
||||
var chunks = src.split(/\/\*t:/);
|
||||
|
||||
var run = function(chunk) {
|
||||
// local shortcuts
|
||||
var is = TestDoc.assertEquals;
|
||||
var isnt = TestDoc.assertNotEquals;
|
||||
var plan = TestDoc.plan;
|
||||
var requires = TestDoc.requires;
|
||||
|
||||
try { eval(chunk); } catch(e) { print("# ERROR! "+e); }
|
||||
}
|
||||
for (var start = -1, end = 0; (start = src.indexOf("/*t:", end)) > end; start = end) {
|
||||
run(
|
||||
src.substring(
|
||||
start+4,
|
||||
(end = src.indexOf("*/", start))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TestDoc.Result = function(verdict, message) {
|
||||
this.verdict = verdict;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
TestDoc.Result.prototype.toString = function() {
|
||||
if (typeof this.verdict == "boolean") {
|
||||
return (this.verdict? "ok" : "not ok") + " " + (++TestDoc.report.counter) + " - " + this.message;
|
||||
}
|
||||
|
||||
return "# " + this.message;
|
||||
}
|
||||
|
||||
TestDoc.requires = function(file) {
|
||||
if (!TestDoc.requires.loaded[file]) {
|
||||
load(file);
|
||||
TestDoc.requires.loaded[file] = true;
|
||||
}
|
||||
}
|
||||
TestDoc.requires.loaded = {};
|
||||
|
||||
TestDoc.report = function() {
|
||||
TestDoc.report.counter = 0;
|
||||
print("1.."+TestDoc.plans);
|
||||
for (var i = 0; i < TestDoc.results.length; i++) {
|
||||
print(TestDoc.results[i]);
|
||||
}
|
||||
print("----------------------------------------");
|
||||
if (TestDoc.fails == 0 && TestDoc.passes == TestDoc.plans) {
|
||||
print("All tests successful.");
|
||||
}
|
||||
else {
|
||||
print("Failed " + TestDoc.fails + "/" + TestDoc.plans + " tests, "+((TestDoc.plans == 0)? 0 : Math.round(TestDoc.passes/(TestDoc.passes+TestDoc.fails)*10000)/100)+"% okay. Planned to run "+TestDoc.plans+", did run "+(TestDoc.passes+TestDoc.fails)+".")
|
||||
}
|
||||
}
|
||||
|
||||
TestDoc.plan = function(n, message) {
|
||||
TestDoc.plans += n;
|
||||
TestDoc.record(new TestDoc.Result(null, message+" ("+n+" tests)"));
|
||||
}
|
||||
|
||||
TestDoc.assertEquals = function(a, b, message) {
|
||||
var result = (a == b);
|
||||
if (!result) message += "\n#\n# " + a + " does not equal " + b + "\n#";
|
||||
TestDoc.record(new TestDoc.Result(result, message));
|
||||
}
|
||||
|
||||
TestDoc.assertNotEquals = function(a, b, message) {
|
||||
var result = (a != b);
|
||||
if (!result) message += "\n#\n# " + a + " equals " + b + "\n#";
|
||||
TestDoc.record(new TestDoc.Result(result, message));
|
||||
}
|
||||
|
||||
TestDoc.readFile = (function(){
|
||||
// rhino
|
||||
if (typeof readFile == "function") {
|
||||
return function(url) {
|
||||
var text = readFile(url);
|
||||
return text || "";
|
||||
}
|
||||
}
|
||||
|
||||
// a web browser
|
||||
else {
|
||||
return function(url) {
|
||||
var httpRequest;
|
||||
|
||||
if (window.XMLHttpRequest) { // Mozilla, Safari, etc
|
||||
httpRequest = new XMLHttpRequest();
|
||||
}
|
||||
else if (window.ActiveXObject) { // IE
|
||||
try {
|
||||
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
|
||||
}
|
||||
catch (e) {
|
||||
try {
|
||||
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!httpRequest) { throw "Cannot create HTTP Request."; }
|
||||
|
||||
httpRequest.open('GET', url, false);
|
||||
httpRequest.send('');
|
||||
if (httpRequest.readyState == 4) {
|
||||
if (httpRequest.status >= 400) {
|
||||
throw "The HTTP Request returned an error code: "+httpRequest.status;
|
||||
}
|
||||
}
|
||||
|
||||
return httpRequest.responseText || "";
|
||||
}
|
||||
}
|
||||
})();
|
|
@ -1,13 +0,0 @@
|
|||
// try: java -jar ../../jsrun.jar runner.js
|
||||
|
||||
load("TestDoc.js");
|
||||
|
||||
TestDoc.prove("../frame/Opt.js");
|
||||
TestDoc.prove("../lib/JSDOC.js");
|
||||
TestDoc.prove("../frame/String.js");
|
||||
TestDoc.prove("../lib/JSDOC/DocTag.js");
|
||||
TestDoc.prove("../lib/JSDOC/DocComment.js");
|
||||
TestDoc.prove("../lib/JSDOC/TokenReader.js");
|
||||
TestDoc.prove("../lib/JSDOC/Symbol.js");
|
||||
|
||||
TestDoc.report();
|
|
@ -1,342 +0,0 @@
|
|||
load("app/frame/Dumper.js");
|
||||
function symbolize(opt) {
|
||||
symbols = null;
|
||||
JSDOC.JsDoc(opt);
|
||||
symbols = JSDOC.JsDoc.symbolSet;
|
||||
}
|
||||
|
||||
var testCases = [
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/overview.js"]});
|
||||
//print(Dumper.dump(symbols));
|
||||
is('symbols.getSymbolByName("My Cool Library").name', 'My Cool Library', 'File overview can be found by alias.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({_: [SYS.pwd+"test/name.js"]});
|
||||
|
||||
is('symbols.getSymbol("Response").name', "Response", 'Virtual class name is found.');
|
||||
is('symbols.getSymbol("Response#text").alias', "Response#text", 'Virtual method name is found.');
|
||||
is('symbols.getSymbol("Response#text").memberOf', "Response", 'Virtual method parent name is found.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/prototype.js"]});
|
||||
|
||||
is('symbols.getSymbol("Article").name', "Article", 'Function set to constructor prototype with inner constructor name is found.');
|
||||
is('symbols.getSymbol("Article").hasMethod("init")', true, 'The initializer method name of prototype function is correct.');
|
||||
is('symbols.getSymbol("Article").hasMember("counter")', true, 'A static property set in the prototype definition is found.');
|
||||
is('symbols.getSymbol("Article").hasMember("title")', true, 'An instance property set in the prototype is found.');
|
||||
is('symbols.getSymbol("Article#title").isStatic', false, 'An instance property has isStatic set to false.');
|
||||
is('symbols.getSymbol("Article.counter").name', "counter", 'A static property set in the initializer has the name set correctly.');
|
||||
is('symbols.getSymbol("Article.counter").memberOf', "Article", 'A static property set in the initializer has the memberOf set correctly.');
|
||||
is('symbols.getSymbol("Article.counter").isStatic', true, 'A static property set in the initializer has isStatic set to true.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, _: [SYS.pwd+"test/prototype_oblit.js"]});
|
||||
|
||||
is('symbols.getSymbol("Article").name', "Article", 'Oblit set to constructor prototype name is found.');
|
||||
is('typeof symbols.getSymbol("Article.prototype")', "undefined", 'The prototype oblit is not a symbol.');
|
||||
is('symbols.getSymbol("Article#getTitle").name', "getTitle", 'The nonstatic method name of prototype oblit is correct.');
|
||||
is('symbols.getSymbol("Article#getTitle").alias', "Article#getTitle", 'The alias of non-static method of prototype oblit is correct.');
|
||||
is('symbols.getSymbol("Article#getTitle").isStatic', false, 'The isStatic of a nonstatic method of prototype oblit is correct.');
|
||||
is('symbols.getSymbol("Article.getTitle").name', "getTitle", 'The static method name of prototype oblit is correct.');
|
||||
is('symbols.getSymbol("Article.getTitle").isStatic', true, 'The isStatic of a static method of prototype oblit is correct.');
|
||||
is('symbols.getSymbol("Article#getTitle").isa', "FUNCTION", 'The isa of non-static method of prototype oblit is correct.');
|
||||
is('symbols.getSymbol("Article.getTitle").alias', "Article.getTitle", 'The alias of a static method of prototype oblit is correct.');
|
||||
is('symbols.getSymbol("Article.getTitle").isa', "FUNCTION", 'The isa of static method of prototype oblit is correct.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/prototype_oblit_constructor.js"]});
|
||||
|
||||
is('symbols.getSymbol("Article").name', "Article", 'Oblit set to constructor prototype with inner constructor name is found.');
|
||||
is('symbols.getSymbol("Article#init").name', "init", 'The initializer method name of prototype oblit is correct.');
|
||||
is('symbols.getSymbol("Article").hasMember("pages")', true, 'Property set by initializer method "this" is on the outer constructor.');
|
||||
is('symbols.getSymbol("Article#Title").name', "Title", 'Name of the inner constructor name is found.');
|
||||
is('symbols.getSymbol("Article#Title").memberOf', "Article", 'The memberOf of the inner constructor name is found.');
|
||||
is('symbols.getSymbol("Article#Title").isa', "CONSTRUCTOR", 'The isa of the inner constructor name is constructor.');
|
||||
is('symbols.getSymbol("Article#Title").hasMember("title")', true, 'A property set on the inner constructor "this" is on the inner constructor.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/inner.js"]});
|
||||
|
||||
is('symbols.getSymbol("Outer").name', "Outer", 'Outer constructor prototype name is found.');
|
||||
is('symbols.getSymbol("Outer").methods.length', 1, 'Inner function doesnt appear as a method of the outer.');
|
||||
is('symbols.getSymbol("Outer").hasMethod("open")', true, 'Outer constructors methods arent affected by inner function.');
|
||||
is('symbols.getSymbol("Outer-Inner").alias', "Outer-Inner", 'Alias of inner function is found.');
|
||||
is('symbols.getSymbol("Outer-Inner").isa', "CONSTRUCTOR", 'isa of inner function constructor is found.');
|
||||
is('symbols.getSymbol("Outer-Inner").memberOf', "Outer", 'The memberOf of inner function is found.');
|
||||
is('symbols.getSymbol("Outer-Inner").name', "Inner", 'The name of inner function is found.');
|
||||
is('symbols.getSymbol("Outer-Inner#name").name', "name", 'A member of the inner function constructor, attached to "this" is found on inner.');
|
||||
is('symbols.getSymbol("Outer-Inner#name").memberOf', "Outer-Inner", 'The memberOf of an inner function member is found.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, _: [SYS.pwd+"test/prototype_nested.js"]});
|
||||
|
||||
is('symbols.getSymbol("Word").name', "Word", 'Base constructor name is found.');
|
||||
is('symbols.getSymbol("Word").hasMethod("reverse")', true, 'Base constructor method is found.');
|
||||
is('symbols.getSymbol("Word").methods.length', 1, 'Base constructor has only one method.');
|
||||
is('symbols.getSymbol("Word").memberOf', "", 'Base constructor memberOf is empty.');
|
||||
is('symbols.getSymbol("Word#reverse").name', "reverse", 'Member of constructor prototype name is found.');
|
||||
is('symbols.getSymbol("Word#reverse").memberOf', "Word", 'Member of constructor prototype memberOf is found.');
|
||||
is('symbols.getSymbol("Word#reverse.utf8").name', "utf8", 'Member of constructor prototype method name is found.');
|
||||
is('symbols.getSymbol("Word#reverse.utf8").memberOf', "Word#reverse", 'Static nested member memberOf is found.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, _: [SYS.pwd+"test/namespace_nested.js"]});
|
||||
|
||||
is('symbols.getSymbol("ns1").name', "ns1", 'Base namespace name is found.');
|
||||
is('symbols.getSymbol("ns1").memberOf', "", 'Base namespace memberOf is empty (its a constructor).');
|
||||
is('symbols.getSymbol("ns1.ns2").name', "ns2", 'Nested namespace name is found.');
|
||||
is('symbols.getSymbol("ns1.ns2").alias', "ns1.ns2", 'Nested namespace alias is found.');
|
||||
is('symbols.getSymbol("ns1.ns2").memberOf', "ns1", 'Nested namespace memberOf is found.');
|
||||
is('symbols.getSymbol("ns1.ns2.Function1").name', "Function1", 'Method of nested namespace name is found.');
|
||||
is('symbols.getSymbol("ns1.ns2.Function1").memberOf', "ns1.ns2", 'Constructor of nested namespace memberOf is found.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/functions_nested.js"]});
|
||||
|
||||
is('symbols.getSymbol("Zop").name', "Zop", 'Any constructor name is found.');
|
||||
is('symbols.getSymbol("Zop").isa', "CONSTRUCTOR", 'It isa constructor.');
|
||||
is('symbols.getSymbol("Zop").hasMethod("zap")', true, 'Its method name, set later, is in methods array.');
|
||||
is('symbols.getSymbol("Foo").name', "Foo", 'The containing constructor name is found.');
|
||||
is('symbols.getSymbol("Foo").hasMethod("methodOne")', true, 'Its method name is found.');
|
||||
is('symbols.getSymbol("Foo").hasMethod("methodTwo")', true, 'Its second method name is found.');
|
||||
is('symbols.getSymbol("Foo#methodOne").alias', "Foo#methodOne", 'A methods alias is found.');
|
||||
is('symbols.getSymbol("Foo#methodOne").isStatic', false, 'A methods is not static.');
|
||||
is('symbols.getSymbol("Bar").name', "Bar", 'A global function declared inside another function is found.');
|
||||
is('symbols.getSymbol("Bar").isa', "FUNCTION", 'It isa function.');
|
||||
is('symbols.getSymbol("Bar").memberOf', "_global_", 'It is global.');
|
||||
is('symbols.getSymbol("Foo-inner").name', "inner", 'An inner functions name is found.');
|
||||
is('symbols.getSymbol("Foo-inner").memberOf', "Foo", 'It is member of the outer function.');
|
||||
is('symbols.getSymbol("Foo-inner").isInner', true, 'It is an inner function.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, _: [SYS.pwd+"test/memberof_constructor.js"]});
|
||||
|
||||
is('symbols.getSymbol("Circle#Tangent").name', "Tangent", 'Constructor set on prototype using @member has correct name.');
|
||||
is('symbols.getSymbol("Circle#Tangent").memberOf', "Circle", 'Constructor set on prototype using @member has correct memberOf.');
|
||||
is('symbols.getSymbol("Circle#Tangent").alias', "Circle#Tangent", 'Constructor set on prototype using @member has correct alias.');
|
||||
is('symbols.getSymbol("Circle#Tangent").isa', "CONSTRUCTOR", 'Constructor set on prototype using @member has correct isa.');
|
||||
is('symbols.getSymbol("Circle#Tangent").isStatic', false, 'Constructor set on prototype using @member is not static.');
|
||||
is('symbols.getSymbol("Circle#Tangent#getDiameter").name', "getDiameter", 'Method set on prototype using @member has correct name.');
|
||||
is('symbols.getSymbol("Circle#Tangent#getDiameter").memberOf', "Circle#Tangent", 'Method set on prototype using @member has correct memberOf.');
|
||||
is('symbols.getSymbol("Circle#Tangent#getDiameter").alias', "Circle#Tangent#getDiameter", 'Method set on prototype using @member has correct alias.');
|
||||
is('symbols.getSymbol("Circle#Tangent#getDiameter").isa', "FUNCTION", 'Method set on prototype using @member has correct isa.');
|
||||
is('symbols.getSymbol("Circle#Tangent#getDiameter").isStatic', false, 'Method set on prototype using @member is not static.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof.js"]});
|
||||
|
||||
is('symbols.getSymbol("pack.install").alias', "pack.install", 'Using @memberOf sets alias, when parent name is in memberOf tag.');
|
||||
is('symbols.getSymbol("pack.install.overwrite").name', "install.overwrite", 'Using @memberOf sets name, even if the name is dotted.');
|
||||
is('symbols.getSymbol("pack.install.overwrite").memberOf', "pack", 'Using @memberOf sets memberOf.');
|
||||
is('symbols.getSymbol("pack.install.overwrite").isStatic', true, 'Using @memberOf with value not ending in octothorp sets isStatic to true.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof2.js"]});
|
||||
|
||||
is('symbols.getSymbol("Foo#bar").alias', "Foo#bar", 'An inner function can be documented as an instance method.');
|
||||
is('symbols.getSymbol("Foo.zip").alias', "Foo.zip", 'An inner function can be documented as a static method.');
|
||||
is('symbols.getSymbol("Foo.Fiz").alias', "Foo.Fiz", 'An inner function can be documented as a static constructor.');
|
||||
is('symbols.getSymbol("Foo.Fiz#fipple").alias', "Foo.Fiz#fipple", 'An inner function can be documented as a static constructor with a method.');
|
||||
is('symbols.getSymbol("Foo#blat").alias', "Foo#blat", 'An global function can be documented as an instance method.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof3.js"]});
|
||||
|
||||
is('symbols.getSymbol("Foo#bar").alias', "Foo#bar", 'A virtual field can be documented as an instance method.');
|
||||
is('symbols.getSymbol("Foo2#bar").alias', "Foo2#bar", 'A virtual field with the same name can be documented as an instance method.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/borrows.js"]});
|
||||
|
||||
is('symbols.getSymbol("Layout").name', "Layout", 'Constructor can be found.');
|
||||
is('symbols.getSymbol("Layout").hasMethod("init")', true, 'Constructor method name can be found.');
|
||||
is('symbols.getSymbol("Layout").hasMember("orientation")', true, 'Constructor property name can be found.');
|
||||
|
||||
is('symbols.getSymbol("Page").hasMethod("reset")', true, 'Second constructor method name can be found.');
|
||||
is('symbols.getSymbol("Page").hasMember("orientation")', true, 'Second constructor borrowed property name can be found in properties.');
|
||||
is('symbols.getSymbol("Page#orientation").memberOf', "Page", 'Second constructor borrowed property memberOf can be found.');
|
||||
is('symbols.getSymbol("Page-getInnerElements").alias', "Page-getInnerElements", 'Can borrow an inner function and it is still inner.');
|
||||
is('symbols.getSymbol("Page.units").alias', "Page.units", 'Can borrow a static function and it is still static.');
|
||||
|
||||
is('symbols.getSymbol("ThreeColumnPage#init").alias', "ThreeColumnPage#init", 'Third constructor method can be found even though method with same name is borrowed.');
|
||||
is('symbols.getSymbol("ThreeColumnPage#reset").alias', "ThreeColumnPage#reset", 'Borrowed method can be found.');
|
||||
is('symbols.getSymbol("ThreeColumnPage#orientation").alias', "ThreeColumnPage#orientation", 'Twice borrowed method can be found.');
|
||||
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/borrows2.js"]});
|
||||
|
||||
is('symbols.getSymbol("Foo").hasMethod("my_zop")', true, 'Borrowed method can be found.');
|
||||
is('symbols.getSymbol("Bar").hasMethod("my_zip")', true, 'Second borrowed method can be found.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/constructs.js"]});
|
||||
|
||||
is('symbols.getSymbol("Person").hasMethod("say")', true, 'The constructs tag creates a class that lends can add a method to.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a: true, _: [SYS.pwd+"test/augments.js", SYS.pwd+"test/augments2.js"]});
|
||||
|
||||
is('symbols.getSymbol("Page").augments[0]', "Layout", 'An augmented class can be found.');
|
||||
is('symbols.getSymbol("Page#reset").alias', "Page#reset", 'Method of augmenter can be found.');
|
||||
is('symbols.getSymbol("Page").hasMethod("Layout#init")', true, 'Method from augmented can be found.');
|
||||
is('symbols.getSymbol("Page").hasMember("Layout#orientation")', true, 'Property from augmented can be found.');
|
||||
is('symbols.getSymbol("Page").methods.length', 3, 'Methods of augmented class are included in methods array.');
|
||||
|
||||
is('symbols.getSymbol("ThreeColumnPage").augments[0]', "Page", 'The extends tag is a synonym for augments.');
|
||||
is('symbols.getSymbol("ThreeColumnPage").hasMethod("ThreeColumnPage#init")', true, 'Local method overrides augmented method of same name.');
|
||||
is('symbols.getSymbol("ThreeColumnPage").methods.length', 3, 'Local method count is right.');
|
||||
|
||||
is('symbols.getSymbol("NewsletterPage").augments[0]', "ThreeColumnPage", 'Can augment across file boundaries.');
|
||||
is('symbols.getSymbol("NewsletterPage").augments.length', 2, 'Multiple augments are supported.');
|
||||
is('symbols.getSymbol("NewsletterPage").inherits[0].alias', "Junkmail#annoy", 'Inherited method with augments.');
|
||||
is('symbols.getSymbol("NewsletterPage").methods.length', 6, 'Methods of augmented class are included in methods array across files.');
|
||||
is('symbols.getSymbol("NewsletterPage").properties.length', 1, 'Properties of augmented class are included in properties array across files.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, _: [SYS.pwd+"test/static_this.js"]});
|
||||
|
||||
is('symbols.getSymbol("box.holder").name', "holder", 'Static namespace name can be found.');
|
||||
is('symbols.getSymbol("box.holder.foo").name', "foo", 'Static namespace method name can be found.');
|
||||
is('symbols.getSymbol("box.holder").isStatic', true, 'Static namespace method is static.');
|
||||
|
||||
is('symbols.getSymbol("box.holder.counter").name', "counter", 'Instance namespace property name set on "this" can be found.');
|
||||
is('symbols.getSymbol("box.holder.counter").alias', "box.holder.counter", 'Instance namespace property alias set on "this" can be found.');
|
||||
is('symbols.getSymbol("box.holder.counter").memberOf', "box.holder", 'Static namespace property memberOf set on "this" can be found.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p: true, _: [SYS.pwd+"test/lend.js"]});
|
||||
|
||||
is('symbols.getSymbol("Person").name', "Person", 'Class defined in lend comment is found.');
|
||||
is('symbols.getSymbol("Person").hasMethod("initialize")', true, 'Lent instance method name can be found.');
|
||||
is('symbols.getSymbol("Person").hasMethod("say")', true, 'Second instance method can be found.');
|
||||
is('symbols.getSymbol("Person#sing").isStatic', false, 'Instance method is known to be not static.');
|
||||
|
||||
is('symbols.getSymbol("Person.getCount").name', "getCount", 'Static method name from second lend comment can be found.');
|
||||
is('symbols.getSymbol("Person.getCount").isStatic', true, 'Static method from second lend comment is known to be static.');
|
||||
|
||||
is('LOG.warnings.filter(function($){if($.indexOf("notok") > -1) return $}).length', 1, 'A warning is emitted when lending to an undocumented parent.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, _: [SYS.pwd+"test/param_inline.js"]});
|
||||
|
||||
is('symbols.getSymbol("Layout").params[0].type', "int", 'Inline param name is set.');
|
||||
is('symbols.getSymbol("Layout").params[0].desc', "The number of columns.", 'Inline param desc is set from comment.');
|
||||
is('symbols.getSymbol("Layout#getElement").params[0].name', "id", 'User defined param documentation takes precedence over parser defined.');
|
||||
is('symbols.getSymbol("Layout#getElement").params[0].isOptional', true, 'Default for param is to not be optional.');
|
||||
is('symbols.getSymbol("Layout#getElement").params[1].isOptional', false, 'Can mark a param as being optional.');
|
||||
is('symbols.getSymbol("Layout#getElement").params[1].type', "number|string", 'Type of inline param doc can have multiple values.');
|
||||
is('symbols.getSymbol("Layout#Canvas").params[0].type', "", 'Type can be not defined for some params.');
|
||||
is('symbols.getSymbol("Layout#Canvas").params[2].type', "int", 'Type can be defined inline for only some params.');
|
||||
is('symbols.getSymbol("Layout#rotate").params.length', 0, 'Docomments inside function sig is ignored without a param.');
|
||||
is('symbols.getSymbol("Layout#init").params[2].type', "zoppler", 'Doc comment type overrides inline type for param with same name.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a: true, _: [SYS.pwd+"test/shared.js", SYS.pwd+"test/shared2.js"]});
|
||||
|
||||
is('symbols.getSymbol("Array#some").name', 'some', 'The name of a symbol in a shared section is found.');
|
||||
is('symbols.getSymbol("Array#some").alias', 'Array#some', 'The alias of a symbol in a shared section is found.');
|
||||
is('symbols.getSymbol("Array#some").desc', "Extension to builtin array.", 'A description can be shared.');
|
||||
is('symbols.getSymbol("Array#filter").desc', "Extension to builtin array.\nChange every element of an array.", 'A shared description is appended.');
|
||||
is('symbols.getSymbol("Queue").desc', "A first in, first out data structure.", 'A description is not shared when outside a shared section.');
|
||||
is('symbols.getSymbol("Queue.rewind").alias', "Queue.rewind", 'Second shared tag can be started.');
|
||||
is('symbols.getSymbol("startOver").alias', "startOver", 'Shared tag doesnt cross over files.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a: true, _: [SYS.pwd+"test/config.js"]});
|
||||
is('symbols.getSymbol("Contact").params[0].name', 'person', 'The name of a param is found.');
|
||||
is('symbols.getSymbol("Contact").params[1].name', 'person.name', 'The name of a param set with a dot name is found.');
|
||||
is('symbols.getSymbol("Contact").params[2].name', 'person.age', 'The name of a second param set with a dot name is found.');
|
||||
is('symbols.getSymbol("Contact").params[4].name', 'connection', 'The name of a param after config is found.');
|
||||
|
||||
is('symbols.getSymbol("Family").params[0].name', 'persons', 'Another name of a param is found.');
|
||||
is('symbols.getSymbol("Family").params[1].name', 'persons.Father', 'The name of a param+config is found.');
|
||||
is('symbols.getSymbol("Family").params[2].name', 'persons.Mother', 'The name of a second param+config is found.');
|
||||
is('symbols.getSymbol("Family").params[3].name', 'persons.Children', 'The name of a third param+config is found.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/ignore.js"]});
|
||||
is('LOG.warnings.filter(function($){if($.indexOf("undocumented symbol Ignored") > -1) return $}).length', 1, 'A warning is emitted when documenting members of an ignored parent.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/functions_anon.js"]});
|
||||
is('symbols.getSymbol("a.b").alias', 'a.b', 'In anonymous constructor this is found to be the container object.');
|
||||
is('symbols.getSymbol("a.f").alias', 'a.f', 'In anonymous constructor this can have a method.');
|
||||
is('symbols.getSymbol("a.c").alias', 'a.c', 'In anonymous constructor method this is found to be the container object.');
|
||||
is('symbols.getSymbol("g").alias', 'g', 'In anonymous function executed inline this is the global.');
|
||||
is('symbols.getSymbol("bar2.p").alias', 'bar2.p', 'In named constructor executed inline this is the container object.');
|
||||
is('symbols.getSymbol("module.pub").alias', 'module.pub', 'In parenthesized anonymous function executed inline function scoped variables arent documented.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/oblit_anon.js"]});
|
||||
is('symbols.getSymbol("opt").name', 'opt', 'Anonymous object properties are created.');
|
||||
is('symbols.getSymbol("opt.conf.keep").alias', 'opt.conf.keep', 'Anonymous object first property is assigned to $anonymous.');
|
||||
is('symbols.getSymbol("opt.conf.base").alias', 'opt.conf.base', 'Anonymous object second property is assigned to $anonymous.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/params_optional.js"]});
|
||||
is('symbols.getSymbol("Document").params.length', 3, 'Correct number of params are found when optional param syntax is used.');
|
||||
is('symbols.getSymbol("Document").params[1].name', "id", 'Name of optional param is found.');
|
||||
is('symbols.getSymbol("Document").params[1].isOptional', true, 'Optional param is marked isOptional.');
|
||||
is('symbols.getSymbol("Document").params[2].name', "title", 'Name of optional param with default value is found.');
|
||||
is('symbols.getSymbol("Document").params[2].isOptional', true, 'Optional param with default value is marked isOptional.');
|
||||
is('symbols.getSymbol("Document").params[2].defaultValue', " This is untitled.", 'Optional param default value is found.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/synonyms.js"]});
|
||||
is('symbols.getSymbol("myObject.myFunc").type', 'function', 'Type can be set to function.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({a:true, p:true, _: [SYS.pwd+"test/event.js"]});
|
||||
is('symbols.getSymbol("Kitchen#event:cakeEaten").isEvent', true, 'Function with event prefix is an event.');
|
||||
is('symbols.getSymbol("Kitchen#cakeEaten").isa', "FUNCTION", 'Function with same name as event isa function.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({x:"js", a:true, _: [SYS.pwd+"test/scripts/"]});
|
||||
is('JSDOC.JsDoc.srcFiles.length', 1, 'Only js files are scanned when -x=js.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({x:"js", a:true, _: [SYS.pwd+"test/exports.js"]});
|
||||
is('symbols.getSymbol("mxn.Map#doThings").name', 'doThings', 'Exports creates a documentation alias that can have methods.');
|
||||
}
|
||||
,
|
||||
function() {
|
||||
symbolize({p:true, a:true, _: [SYS.pwd+"test/module.js"]});
|
||||
is('symbols.getSymbol("myProject.myModule.myPublicMethod").name', 'myPublicMethod', 'A function wrapped in parens can be recognized.');
|
||||
is('symbols.getSymbol("myProject.myModule-myPrivateMethod").name', 'myPrivateMethod', 'A private method in the scope of a function wrapped in parens can be recognized.');
|
||||
is('symbols.getSymbol("myProject.myModule-myPrivateVar").name', 'myPrivateVar', 'A private member in the scope of a function wrapped in parens can be recognized.');
|
||||
}
|
||||
];
|
||||
|
||||
//// run and print results
|
||||
print(testrun(testCases));
|
|
@ -1,24 +0,0 @@
|
|||
String.prototype.reverse = function() {
|
||||
}
|
||||
|
||||
String.prototype.reverse.utf8 = function() {
|
||||
}
|
||||
|
||||
Function.count = function() {
|
||||
}
|
||||
|
||||
/** @memberOf Function */
|
||||
Function.count.reset = function() {
|
||||
}
|
||||
|
||||
/** @memberOf Function */
|
||||
count.getValue = function() {
|
||||
}
|
||||
|
||||
/** @memberOf Function.prototype */
|
||||
getSig = function() {
|
||||
}
|
||||
|
||||
/** @memberOf Function.prototype */
|
||||
Function.prototype.getProps = function() {
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
/**
|
||||
* @name bar
|
||||
* @namespace
|
||||
*/
|
||||
|
||||
new function() {
|
||||
/**
|
||||
* @name bar-foo
|
||||
* @function
|
||||
* @param {number} x
|
||||
*/
|
||||
function foo(x) {
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
@constructor
|
||||
*/
|
||||
function Layout(p) {
|
||||
this.init = function(p) {
|
||||
}
|
||||
|
||||
this.getId = function() {
|
||||
}
|
||||
|
||||
/** @type Page */
|
||||
this.orientation = "landscape";
|
||||
}
|
||||
|
||||
/**
|
||||
@constructor
|
||||
@augments Layout
|
||||
*/
|
||||
function Page() {
|
||||
this.reset = function(b) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@extends Page
|
||||
@constructor
|
||||
*/
|
||||
function ThreeColumnPage() {
|
||||
this.init = function(resetCode) {
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
@constructor
|
||||
*/
|
||||
function LibraryItem() {
|
||||
this.reserve = function() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@constructor
|
||||
*/
|
||||
function Junkmail() {
|
||||
this.annoy = function() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@inherits Junkmail.prototype.annoy as pester
|
||||
@augments ThreeColumnPage
|
||||
@augments LibraryItem
|
||||
@constructor
|
||||
*/
|
||||
function NewsletterPage() {
|
||||
this.getHeadline = function() {
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
@constructor
|
||||
*/
|
||||
function Layout(p) {
|
||||
/** initilize 1 */
|
||||
this.init = function(p) {
|
||||
}
|
||||
|
||||
/** get the id */
|
||||
this.getId = function() {
|
||||
}
|
||||
|
||||
/** @type string */
|
||||
this.orientation = "landscape";
|
||||
|
||||
function getInnerElements(elementSecretId){
|
||||
}
|
||||
}
|
||||
|
||||
/** A static method. */
|
||||
Layout.units = function() {
|
||||
}
|
||||
|
||||
/**
|
||||
@constructor
|
||||
@borrows Layout#orientation
|
||||
@borrows Layout-getInnerElements
|
||||
@borrows Layout.units
|
||||
*/
|
||||
function Page() {
|
||||
/** reset the page */
|
||||
this.reset = function(b) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@constructor
|
||||
@borrows Layout.prototype.orientation as this.orientation
|
||||
@borrows Layout.prototype.init as #init
|
||||
@inherits Page.prototype.reset as #reset
|
||||
*/
|
||||
function ThreeColumnPage() {
|
||||
/** initilize 2 */
|
||||
this.init = function(p) {
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
// testing circular borrows
|
||||
|
||||
/**
|
||||
@class
|
||||
@borrows Bar#zop as this.my_zop
|
||||
*/
|
||||
function Foo() {
|
||||
/** this is a zip. */
|
||||
this.zip = function() {}
|
||||
|
||||
this.my_zop = new Bar().zop;
|
||||
}
|
||||
|
||||
/**
|
||||
@class
|
||||
@borrows Foo#zip as this.my_zip
|
||||
*/
|
||||
function Bar() {
|
||||
/** this is a zop. */
|
||||
this.zop = function() {}
|
||||
|
||||
this.my_zip = new Foo().zip;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/**
|
||||
* @constructor
|
||||
* @param person The person.
|
||||
* @param {string} person.name The person's name.
|
||||
* @config {integer} age The person's age.
|
||||
* @config [id=1] Optional id number to use.
|
||||
* @param connection
|
||||
*/
|
||||
function Contact(person, connection) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param persons
|
||||
* @config {string} Father The paternal person.
|
||||
* @config {string} Mother The maternal person.
|
||||
* @config {string[]} Children And the rest.
|
||||
*/
|
||||
function Family(/**Object*/persons) {
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
var Person = makeClass(
|
||||
/**
|
||||
@scope Person
|
||||
*/
|
||||
{
|
||||
/**
|
||||
This is just another way to define a constructor.
|
||||
@constructs
|
||||
@param {string} name The name of the person.
|
||||
*/
|
||||
initialize: function(name) {
|
||||
this.name = name;
|
||||
},
|
||||
say: function(message) {
|
||||
return this.name + " says: " + message;
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
/**
|
||||
* @Constructor
|
||||
* @desc 配置文件
|
||||
* @class 什么也不返回
|
||||
*/
|
||||
function Test(conf) {
|
||||
// do something;
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
/**
|
||||
* @Constructor
|
||||
* @desc ðïîÛ
|
||||
* @class ßàáâãäåæçèçìëêíîï °±²³´µ¡¶·¸¹
|
||||
*/
|
||||
function Test(conf) {
|
||||
// do something;
|
||||
}
|
||||
|
||||
// run with commanline option -e=iso-8859-5
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/**
|
||||
* @name Kitchen
|
||||
* @constructor
|
||||
* @fires Bakery#event:donutOrdered
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fired when some cake is eaten.
|
||||
* @name Kitchen#event:cakeEaten
|
||||
* @function
|
||||
* @param {Number} pieces The number of pieces eaten.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find out if cake was eaten.
|
||||
* @name Kitchen#cakeEaten
|
||||
* @function
|
||||
* @param {Boolean} wasEaten
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name getDesert
|
||||
* @function
|
||||
* @fires Kitchen#event:cakeEaten
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name Bakery
|
||||
* @constructor
|
||||
* @extends Kitchen
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fired when a donut order is made.
|
||||
* @name Bakery#event:donutOrdered
|
||||
* @event
|
||||
* @param {Event} e The event object.
|
||||
* @param {String} [e.topping] Optional sprinkles.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @borrows Bakery#event:donutOrdered as this.event:cakeOrdered
|
||||
*/
|
||||
function CakeShop() {
|
||||
}
|
||||
|
||||
/** @event */
|
||||
CakeShop.prototype.icingReady = function(isPink) {
|
||||
}
|
||||
|
||||
/** @event */
|
||||
function amHungry(/**Boolean*/enoughToEatAHorse) {
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
/** @namespace */
|
||||
var mxn = {};
|
||||
|
||||
(function(){
|
||||
/** @exports Map as mxn.Map */
|
||||
var Map =
|
||||
/** @constructor */
|
||||
mxn.Map = function() {
|
||||
};
|
||||
|
||||
/** A method. */
|
||||
Map.prototype.doThings = function() {
|
||||
};
|
||||
})();
|
|
@ -1,39 +0,0 @@
|
|||
/** an anonymous constructor executed inline */
|
||||
a = new function() {
|
||||
/** a.b*/
|
||||
this.b = 1;
|
||||
/** a.f */
|
||||
this.f = function() {
|
||||
/** a.c */
|
||||
this.c = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
named function executed inline
|
||||
*/
|
||||
bar1 = function Zoola1() {
|
||||
/** property of global */
|
||||
this.g = 1;
|
||||
}();
|
||||
|
||||
/**
|
||||
named constructor executed inline
|
||||
*/
|
||||
bar2 = new function Zoola2() {
|
||||
/** property of bar */
|
||||
this.p = 1;
|
||||
};
|
||||
|
||||
/** module pattern */
|
||||
module = (function () {
|
||||
/** won't appear in documentation */
|
||||
var priv = 1;
|
||||
|
||||
/** @scope module */
|
||||
return {
|
||||
/** will appear as a property of module */
|
||||
pub: 1
|
||||
}
|
||||
})();
|
|
@ -1,33 +0,0 @@
|
|||
/** @constructor */
|
||||
function Zop() {
|
||||
}
|
||||
|
||||
/**
|
||||
@class
|
||||
*/
|
||||
Foo = function(id) {
|
||||
// this is a bit twisted, but if you call Foo() you will then
|
||||
// modify Foo(). This is kinda, sorta non-insane, because you
|
||||
// would have to call Foo() 100% of the time to use Foo's methods
|
||||
Foo.prototype.methodOne = function(bar) {
|
||||
alert(bar);
|
||||
};
|
||||
|
||||
// same again
|
||||
Foo.prototype.methodTwo = function(bar2) {
|
||||
alert(bar2);
|
||||
};
|
||||
|
||||
// and these are only executed if the enclosing function is actually called
|
||||
// and who knows if that will ever happen?
|
||||
Bar = function(pez) {
|
||||
alert(pez);
|
||||
};
|
||||
Zop.prototype.zap = function(p){
|
||||
alert(p);
|
||||
};
|
||||
|
||||
// but this is only visible inside Foo
|
||||
function inner() {
|
||||
}
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
/** ecks */
|
||||
var x = [1, 2, 4];
|
||||
|
||||
var y = {
|
||||
foo: function(){
|
||||
}
|
||||
}
|
||||
|
||||
bar = function() {
|
||||
}
|
||||
|
||||
function zop() {
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue