mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-common
synced 2025-12-27 15:08:21 +00:00
Compare commits
No commits in common. "master" and "before-split2" have entirely different histories.
master
...
before-spl
@ -1,52 +0,0 @@
|
|||||||
image: fedora:latest
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- >
|
|
||||||
dnf install git libtool make libasan gawk
|
|
||||||
python3 python3-pyparsing glib-networking
|
|
||||||
meson ninja-build gdk-pixbuf2-devel
|
|
||||||
glib2-devel pixman-devel openssl-devel libjpeg-devel
|
|
||||||
libcacard-devel cyrus-sasl-devel lz4-devel opus-devel
|
|
||||||
gstreamer1-devel gstreamer1-plugins-base-devel
|
|
||||||
-y
|
|
||||||
- git clone ${CI_REPOSITORY_URL/spice-common.git/spice-protocol.git}
|
|
||||||
- meson --buildtype=release spice-protocol build-spice-protocol --prefix=/usr --werror
|
|
||||||
- ninja -C build-spice-protocol install
|
|
||||||
|
|
||||||
makecheck:
|
|
||||||
script:
|
|
||||||
- >
|
|
||||||
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
|
|
||||||
LDFLAGS='-fsanitize=address -lasan'
|
|
||||||
./autogen.sh --enable-extra-checks
|
|
||||||
- make
|
|
||||||
- make check || (cat tests/test-suite.log && exit 1)
|
|
||||||
|
|
||||||
meson-makecheck:
|
|
||||||
script:
|
|
||||||
- >
|
|
||||||
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
|
|
||||||
LDFLAGS='-fsanitize=address -lasan'
|
|
||||||
meson build -Dextra-checks=true || (cat build/meson-logs/meson-log.txt && exit 1)
|
|
||||||
- ninja -C build
|
|
||||||
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
|
||||||
|
|
||||||
make-win:
|
|
||||||
script:
|
|
||||||
- >
|
|
||||||
dnf install mingw64-gcc mingw64-pkg-config mingw64-pixman mingw64-openssl
|
|
||||||
mingw64-opus mingw64-glib2 mingw64-glib-networking mingw64-gdk-pixbuf
|
|
||||||
'wine-core(x86-64)'
|
|
||||||
-y
|
|
||||||
- mkdir spice-protocol/build
|
|
||||||
- (cd spice-protocol/build && mingw64-meson --werror && ninja install)
|
|
||||||
- NOCONFIGURE=yes ./autogen.sh
|
|
||||||
- export WINEPATH='Z:\usr\x86_64-w64-mingw32\sys-root\mingw\bin'
|
|
||||||
- >
|
|
||||||
PYTHON=python3
|
|
||||||
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
|
|
||||||
LDFLAGS='-fsanitize=address -lasan'
|
|
||||||
mingw64-configure --enable-extra-checks
|
|
||||||
- make
|
|
||||||
- export LANG=en_US.UTF-8
|
|
||||||
- make LOG_COMPILER=wine check || (cat tests/test-suite.log && exit 1)
|
|
||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "common/recorder"]
|
|
||||||
path = common/recorder
|
|
||||||
url = https://github.com/c3d/recorder.git
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
[gitpublishprofile "default"]
|
|
||||||
to = spice-devel@lists.freedesktop.org
|
|
||||||
prefix = PATCH spice-common
|
|
||||||
502
COPYING
502
COPYING
@ -1,502 +0,0 @@
|
|||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 2.1, February 1999
|
|
||||||
|
|
||||||
Copyright (C) 1991, 1999 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.
|
|
||||||
|
|
||||||
[This is the first released version of the Lesser GPL. It also counts
|
|
||||||
as the successor of the GNU Library Public License, version 2, hence
|
|
||||||
the version number 2.1.]
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
Licenses are intended to guarantee your freedom to share and change
|
|
||||||
free software--to make sure the software is free for all its users.
|
|
||||||
|
|
||||||
This license, the Lesser General Public License, applies to some
|
|
||||||
specially designated software packages--typically libraries--of the
|
|
||||||
Free Software Foundation and other authors who decide to use it. You
|
|
||||||
can use it too, but we suggest you first think carefully about whether
|
|
||||||
this license or the ordinary General Public License is the better
|
|
||||||
strategy to use in any particular case, based on the explanations below.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom of use,
|
|
||||||
not price. Our General Public Licenses are designed to make sure that
|
|
||||||
you have the freedom to distribute copies of free software (and charge
|
|
||||||
for this service if you wish); that you receive source code or can get
|
|
||||||
it if you want it; that you can change the software and use pieces of
|
|
||||||
it in new free programs; and that you are informed that you can do
|
|
||||||
these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
distributors to deny you these rights or to ask you to surrender these
|
|
||||||
rights. These restrictions translate to certain responsibilities for
|
|
||||||
you if you distribute copies of the library or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of the library, whether gratis
|
|
||||||
or for a fee, you must give the recipients all the rights that we gave
|
|
||||||
you. You must make sure that they, too, receive or can get the source
|
|
||||||
code. If you link other code with the library, you must provide
|
|
||||||
complete object files to the recipients, so that they can relink them
|
|
||||||
with the library after making changes to the library and recompiling
|
|
||||||
it. And you must show them these terms so they know their rights.
|
|
||||||
|
|
||||||
We protect your rights with a two-step method: (1) we copyright the
|
|
||||||
library, and (2) we offer you this license, which gives you legal
|
|
||||||
permission to copy, distribute and/or modify the library.
|
|
||||||
|
|
||||||
To protect each distributor, we want to make it very clear that
|
|
||||||
there is no warranty for the free library. Also, if the library is
|
|
||||||
modified by someone else and passed on, the recipients should know
|
|
||||||
that what they have is not the original version, so that the original
|
|
||||||
author's reputation will not be affected by problems that might be
|
|
||||||
introduced by others.
|
|
||||||
|
|
||||||
Finally, software patents pose a constant threat to the existence of
|
|
||||||
any free program. We wish to make sure that a company cannot
|
|
||||||
effectively restrict the users of a free program by obtaining a
|
|
||||||
restrictive license from a patent holder. Therefore, we insist that
|
|
||||||
any patent license obtained for a version of the library must be
|
|
||||||
consistent with the full freedom of use specified in this license.
|
|
||||||
|
|
||||||
Most GNU software, including some libraries, is covered by the
|
|
||||||
ordinary GNU General Public License. This license, the GNU Lesser
|
|
||||||
General Public License, applies to certain designated libraries, and
|
|
||||||
is quite different from the ordinary General Public License. We use
|
|
||||||
this license for certain libraries in order to permit linking those
|
|
||||||
libraries into non-free programs.
|
|
||||||
|
|
||||||
When a program is linked with a library, whether statically or using
|
|
||||||
a shared library, the combination of the two is legally speaking a
|
|
||||||
combined work, a derivative of the original library. The ordinary
|
|
||||||
General Public License therefore permits such linking only if the
|
|
||||||
entire combination fits its criteria of freedom. The Lesser General
|
|
||||||
Public License permits more lax criteria for linking other code with
|
|
||||||
the library.
|
|
||||||
|
|
||||||
We call this license the "Lesser" General Public License because it
|
|
||||||
does Less to protect the user's freedom than the ordinary General
|
|
||||||
Public License. It also provides other free software developers Less
|
|
||||||
of an advantage over competing non-free programs. These disadvantages
|
|
||||||
are the reason we use the ordinary General Public License for many
|
|
||||||
libraries. However, the Lesser license provides advantages in certain
|
|
||||||
special circumstances.
|
|
||||||
|
|
||||||
For example, on rare occasions, there may be a special need to
|
|
||||||
encourage the widest possible use of a certain library, so that it becomes
|
|
||||||
a de-facto standard. To achieve this, non-free programs must be
|
|
||||||
allowed to use the library. A more frequent case is that a free
|
|
||||||
library does the same job as widely used non-free libraries. In this
|
|
||||||
case, there is little to gain by limiting the free library to free
|
|
||||||
software only, so we use the Lesser General Public License.
|
|
||||||
|
|
||||||
In other cases, permission to use a particular library in non-free
|
|
||||||
programs enables a greater number of people to use a large body of
|
|
||||||
free software. For example, permission to use the GNU C Library in
|
|
||||||
non-free programs enables many more people to use the whole GNU
|
|
||||||
operating system, as well as its variant, the GNU/Linux operating
|
|
||||||
system.
|
|
||||||
|
|
||||||
Although the Lesser General Public License is Less protective of the
|
|
||||||
users' freedom, it does ensure that the user of a program that is
|
|
||||||
linked with the Library has the freedom and the wherewithal to run
|
|
||||||
that program using a modified version of the Library.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow. Pay close attention to the difference between a
|
|
||||||
"work based on the library" and a "work that uses the library". The
|
|
||||||
former contains code derived from the library, whereas the latter must
|
|
||||||
be combined with the library in order to run.
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License Agreement applies to any software library or other
|
|
||||||
program which contains a notice placed by the copyright holder or
|
|
||||||
other authorized party saying it may be distributed under the terms of
|
|
||||||
this Lesser General Public License (also called "this License").
|
|
||||||
Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
A "library" means a collection of software functions and/or data
|
|
||||||
prepared so as to be conveniently linked with application programs
|
|
||||||
(which use some of those functions and data) to form executables.
|
|
||||||
|
|
||||||
The "Library", below, refers to any such software library or work
|
|
||||||
which has been distributed under these terms. A "work based on the
|
|
||||||
Library" means either the Library or any derivative work under
|
|
||||||
copyright law: that is to say, a work containing the Library or a
|
|
||||||
portion of it, either verbatim or with modifications and/or translated
|
|
||||||
straightforwardly into another language. (Hereinafter, translation is
|
|
||||||
included without limitation in the term "modification".)
|
|
||||||
|
|
||||||
"Source code" for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For a library, complete source code means
|
|
||||||
all the source code for all modules it contains, plus any associated
|
|
||||||
interface definition files, plus the scripts used to control compilation
|
|
||||||
and installation of the library.
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running a program using the Library is not restricted, and output from
|
|
||||||
such a program is covered only if its contents constitute a work based
|
|
||||||
on the Library (independent of the use of the Library in a tool for
|
|
||||||
writing it). Whether that is true depends on what the Library does
|
|
||||||
and what the program that uses the Library does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Library's
|
|
||||||
complete source code as you receive it, in any medium, provided that
|
|
||||||
you conspicuously and appropriately publish on each copy an
|
|
||||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
|
||||||
all the notices that refer to this License and to the absence of any
|
|
||||||
warranty; and distribute a copy of this License along with the
|
|
||||||
Library.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy,
|
|
||||||
and you may at your option offer warranty protection in exchange for a
|
|
||||||
fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Library or any portion
|
|
||||||
of it, thus forming a work based on the Library, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The modified work must itself be a software library.
|
|
||||||
|
|
||||||
b) You must cause the files modified to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
c) You must cause the whole of the work to be licensed at no
|
|
||||||
charge to all third parties under the terms of this License.
|
|
||||||
|
|
||||||
d) If a facility in the modified Library refers to a function or a
|
|
||||||
table of data to be supplied by an application program that uses
|
|
||||||
the facility, other than as an argument passed when the facility
|
|
||||||
is invoked, then you must make a good faith effort to ensure that,
|
|
||||||
in the event an application does not supply such function or
|
|
||||||
table, the facility still operates, and performs whatever part of
|
|
||||||
its purpose remains meaningful.
|
|
||||||
|
|
||||||
(For example, a function in a library to compute square roots has
|
|
||||||
a purpose that is entirely well-defined independent of the
|
|
||||||
application. Therefore, Subsection 2d requires that any
|
|
||||||
application-supplied function or table used by this function must
|
|
||||||
be optional: if the application does not supply it, the square
|
|
||||||
root function must still compute square roots.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Library,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Library, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote
|
|
||||||
it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Library.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Library
|
|
||||||
with the Library (or with a work based on the Library) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
|
||||||
License instead of this License to a given copy of the Library. To do
|
|
||||||
this, you must alter all the notices that refer to this License, so
|
|
||||||
that they refer to the ordinary GNU General Public License, version 2,
|
|
||||||
instead of to this License. (If a newer version than version 2 of the
|
|
||||||
ordinary GNU General Public License has appeared, then you can specify
|
|
||||||
that version instead if you wish.) Do not make any other change in
|
|
||||||
these notices.
|
|
||||||
|
|
||||||
Once this change is made in a given copy, it is irreversible for
|
|
||||||
that copy, so the ordinary GNU General Public License applies to all
|
|
||||||
subsequent copies and derivative works made from that copy.
|
|
||||||
|
|
||||||
This option is useful when you wish to copy part of the code of
|
|
||||||
the Library into a program that is not a library.
|
|
||||||
|
|
||||||
4. You may copy and distribute the Library (or a portion or
|
|
||||||
derivative of it, under Section 2) in object code or executable form
|
|
||||||
under the terms of Sections 1 and 2 above provided that you accompany
|
|
||||||
it with the complete corresponding machine-readable source code, which
|
|
||||||
must be distributed under the terms of Sections 1 and 2 above on a
|
|
||||||
medium customarily used for software interchange.
|
|
||||||
|
|
||||||
If distribution of object code is made by offering access to copy
|
|
||||||
from a designated place, then offering equivalent access to copy the
|
|
||||||
source code from the same place satisfies the requirement to
|
|
||||||
distribute the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
5. A program that contains no derivative of any portion of the
|
|
||||||
Library, but is designed to work with the Library by being compiled or
|
|
||||||
linked with it, is called a "work that uses the Library". Such a
|
|
||||||
work, in isolation, is not a derivative work of the Library, and
|
|
||||||
therefore falls outside the scope of this License.
|
|
||||||
|
|
||||||
However, linking a "work that uses the Library" with the Library
|
|
||||||
creates an executable that is a derivative of the Library (because it
|
|
||||||
contains portions of the Library), rather than a "work that uses the
|
|
||||||
library". The executable is therefore covered by this License.
|
|
||||||
Section 6 states terms for distribution of such executables.
|
|
||||||
|
|
||||||
When a "work that uses the Library" uses material from a header file
|
|
||||||
that is part of the Library, the object code for the work may be a
|
|
||||||
derivative work of the Library even though the source code is not.
|
|
||||||
Whether this is true is especially significant if the work can be
|
|
||||||
linked without the Library, or if the work is itself a library. The
|
|
||||||
threshold for this to be true is not precisely defined by law.
|
|
||||||
|
|
||||||
If such an object file uses only numerical parameters, data
|
|
||||||
structure layouts and accessors, and small macros and small inline
|
|
||||||
functions (ten lines or less in length), then the use of the object
|
|
||||||
file is unrestricted, regardless of whether it is legally a derivative
|
|
||||||
work. (Executables containing this object code plus portions of the
|
|
||||||
Library will still fall under Section 6.)
|
|
||||||
|
|
||||||
Otherwise, if the work is a derivative of the Library, you may
|
|
||||||
distribute the object code for the work under the terms of Section 6.
|
|
||||||
Any executables containing that work also fall under Section 6,
|
|
||||||
whether or not they are linked directly with the Library itself.
|
|
||||||
|
|
||||||
6. As an exception to the Sections above, you may also combine or
|
|
||||||
link a "work that uses the Library" with the Library to produce a
|
|
||||||
work containing portions of the Library, and distribute that work
|
|
||||||
under terms of your choice, provided that the terms permit
|
|
||||||
modification of the work for the customer's own use and reverse
|
|
||||||
engineering for debugging such modifications.
|
|
||||||
|
|
||||||
You must give prominent notice with each copy of the work that the
|
|
||||||
Library is used in it and that the Library and its use are covered by
|
|
||||||
this License. You must supply a copy of this License. If the work
|
|
||||||
during execution displays copyright notices, you must include the
|
|
||||||
copyright notice for the Library among them, as well as a reference
|
|
||||||
directing the user to the copy of this License. Also, you must do one
|
|
||||||
of these things:
|
|
||||||
|
|
||||||
a) Accompany the work with the complete corresponding
|
|
||||||
machine-readable source code for the Library including whatever
|
|
||||||
changes were used in the work (which must be distributed under
|
|
||||||
Sections 1 and 2 above); and, if the work is an executable linked
|
|
||||||
with the Library, with the complete machine-readable "work that
|
|
||||||
uses the Library", as object code and/or source code, so that the
|
|
||||||
user can modify the Library and then relink to produce a modified
|
|
||||||
executable containing the modified Library. (It is understood
|
|
||||||
that the user who changes the contents of definitions files in the
|
|
||||||
Library will not necessarily be able to recompile the application
|
|
||||||
to use the modified definitions.)
|
|
||||||
|
|
||||||
b) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (1) uses at run time a
|
|
||||||
copy of the library already present on the user's computer system,
|
|
||||||
rather than copying library functions into the executable, and (2)
|
|
||||||
will operate properly with a modified version of the library, if
|
|
||||||
the user installs one, as long as the modified version is
|
|
||||||
interface-compatible with the version that the work was made with.
|
|
||||||
|
|
||||||
c) Accompany the work with a written offer, valid for at
|
|
||||||
least three years, to give the same user the materials
|
|
||||||
specified in Subsection 6a, above, for a charge no more
|
|
||||||
than the cost of performing this distribution.
|
|
||||||
|
|
||||||
d) If distribution of the work is made by offering access to copy
|
|
||||||
from a designated place, offer equivalent access to copy the above
|
|
||||||
specified materials from the same place.
|
|
||||||
|
|
||||||
e) Verify that the user has already received a copy of these
|
|
||||||
materials or that you have already sent this user a copy.
|
|
||||||
|
|
||||||
For an executable, the required form of the "work that uses the
|
|
||||||
Library" must include any data and utility programs needed for
|
|
||||||
reproducing the executable from it. However, as a special exception,
|
|
||||||
the materials to be distributed need not include anything that is
|
|
||||||
normally distributed (in either source or binary form) with the major
|
|
||||||
components (compiler, kernel, and so on) of the operating system on
|
|
||||||
which the executable runs, unless that component itself accompanies
|
|
||||||
the executable.
|
|
||||||
|
|
||||||
It may happen that this requirement contradicts the license
|
|
||||||
restrictions of other proprietary libraries that do not normally
|
|
||||||
accompany the operating system. Such a contradiction means you cannot
|
|
||||||
use both them and the Library together in an executable that you
|
|
||||||
distribute.
|
|
||||||
|
|
||||||
7. You may place library facilities that are a work based on the
|
|
||||||
Library side-by-side in a single library together with other library
|
|
||||||
facilities not covered by this License, and distribute such a combined
|
|
||||||
library, provided that the separate distribution of the work based on
|
|
||||||
the Library and of the other library facilities is otherwise
|
|
||||||
permitted, and provided that you do these two things:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work
|
|
||||||
based on the Library, uncombined with any other library
|
|
||||||
facilities. This must be distributed under the terms of the
|
|
||||||
Sections above.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library of the fact
|
|
||||||
that part of it is a work based on the Library, and explaining
|
|
||||||
where to find the accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
8. You may not copy, modify, sublicense, link with, or distribute
|
|
||||||
the Library except as expressly provided under this License. Any
|
|
||||||
attempt otherwise to copy, modify, sublicense, link with, or
|
|
||||||
distribute the Library is void, and will automatically terminate your
|
|
||||||
rights under this License. However, parties who have received copies,
|
|
||||||
or rights, from you under this License will not have their licenses
|
|
||||||
terminated so long as such parties remain in full compliance.
|
|
||||||
|
|
||||||
9. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Library or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Library (or any work based on the
|
|
||||||
Library), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Library or works based on it.
|
|
||||||
|
|
||||||
10. Each time you redistribute the Library (or any work based on the
|
|
||||||
Library), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute, link with or modify the Library
|
|
||||||
subject to these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties with
|
|
||||||
this License.
|
|
||||||
|
|
||||||
11. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Library at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Library by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Library.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under any
|
|
||||||
particular circumstance, the balance of the section is intended to apply,
|
|
||||||
and the section as a whole is intended to apply in other circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
12. If the distribution and/or use of the Library is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Library under this License may add
|
|
||||||
an explicit geographical distribution limitation excluding those countries,
|
|
||||||
so that distribution is permitted only in or among countries not thus
|
|
||||||
excluded. In such case, this License incorporates the limitation as if
|
|
||||||
written in the body of this License.
|
|
||||||
|
|
||||||
13. The Free Software Foundation may publish revised and/or new
|
|
||||||
versions of the Lesser General Public License from time to time.
|
|
||||||
Such new versions will be similar in spirit to the present version,
|
|
||||||
but may differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Library
|
|
||||||
specifies a version number of this License which applies to it and
|
|
||||||
"any later version", you have the option of following the terms and
|
|
||||||
conditions either of that version or of any later version published by
|
|
||||||
the Free Software Foundation. If the Library does not specify a
|
|
||||||
license version number, you may choose any version ever published by
|
|
||||||
the Free Software Foundation.
|
|
||||||
|
|
||||||
14. If you wish to incorporate parts of the Library into other free
|
|
||||||
programs whose distribution conditions are incompatible with these,
|
|
||||||
write to the author to ask for permission. For software which is
|
|
||||||
copyrighted by the Free Software Foundation, write to the Free
|
|
||||||
Software Foundation; we sometimes make exceptions for this. Our
|
|
||||||
decision will be guided by the two goals of preserving the free status
|
|
||||||
of all derivatives of our free software and of promoting the sharing
|
|
||||||
and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
|
||||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
|
||||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
|
||||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
|
||||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
|
||||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
|
||||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
|
||||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
|
||||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
|
||||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
|
||||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
|
||||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
|
||||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
|
||||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|
||||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Libraries
|
|
||||||
|
|
||||||
If you develop a new library, and you want it to be of the greatest
|
|
||||||
possible use to the public, we recommend making it free software that
|
|
||||||
everyone can redistribute and change. You can do so by permitting
|
|
||||||
redistribution under these terms (or, alternatively, under the terms of the
|
|
||||||
ordinary General Public License).
|
|
||||||
|
|
||||||
To apply these terms, attach the following notices to the library. It is
|
|
||||||
safest to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least the
|
|
||||||
"copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the library's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
|
||||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1990
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
That's all there is to it!
|
|
||||||
33
Makefile.am
33
Makefile.am
@ -1,33 +0,0 @@
|
|||||||
NULL =
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
|
||||||
|
|
||||||
SUBDIRS = python_modules common docs
|
|
||||||
|
|
||||||
if ENABLE_TESTS
|
|
||||||
SUBDIRS += tests
|
|
||||||
endif
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
meson.build \
|
|
||||||
meson_options.txt \
|
|
||||||
spice_codegen.py \
|
|
||||||
spice.proto \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
DISTCLEANFILES = *.pyc
|
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = \
|
|
||||||
$(srcdir)/INSTALL \
|
|
||||||
$(srcdir)/aclocal.m4 \
|
|
||||||
$(srcdir)/autoscan.log \
|
|
||||||
$(srcdir)/build-aux \
|
|
||||||
$(srcdir)/config.h.in \
|
|
||||||
$(srcdir)/m4/libtool.m4 \
|
|
||||||
$(srcdir)/m4/ltoptions.m4 \
|
|
||||||
$(srcdir)/m4/ltsugar.m4 \
|
|
||||||
$(srcdir)/m4/ltversion.m4 \
|
|
||||||
$(srcdir)/m4/lt~obsolete.m4 \
|
|
||||||
`find "$(srcdir)" -type f -name Makefile.in -print` \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
-include $(top_srcdir)/git.mk
|
|
||||||
17
autogen.sh
17
autogen.sh
@ -1,17 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e # exit on errors
|
|
||||||
|
|
||||||
srcdir=`dirname $0`
|
|
||||||
test -z "$srcdir" && srcdir=.
|
|
||||||
|
|
||||||
olddir=`pwd`
|
|
||||||
cd "$srcdir"
|
|
||||||
|
|
||||||
mkdir -p m4
|
|
||||||
autoreconf --verbose --force --install
|
|
||||||
|
|
||||||
cd "$olddir"
|
|
||||||
if [ -z "$NOCONFIGURE" ]; then
|
|
||||||
"$srcdir"/configure --enable-maintainer-mode --enable-python-checks ${1+"$@"}
|
|
||||||
fi
|
|
||||||
9
common/.gitignore
vendored
Normal file
9
common/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
*.loT
|
||||||
|
*.o
|
||||||
|
.deps
|
||||||
|
.dirstamp
|
||||||
|
.libs
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
@ -1,44 +1,27 @@
|
|||||||
|
if OS_WIN32
|
||||||
|
SUBDIRS = win
|
||||||
|
endif
|
||||||
|
|
||||||
NULL =
|
NULL =
|
||||||
|
|
||||||
# Avoid need for python(pyparsing) by end users
|
noinst_LTLIBRARIES = libspice-common.la
|
||||||
CLIENT_MARSHALLERS = \
|
|
||||||
generated_client_demarshallers.c \
|
|
||||||
generated_client_marshallers.c \
|
|
||||||
generated_client_marshallers.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
SERVER_MARSHALLERS = \
|
|
||||||
generated_server_demarshallers.c \
|
|
||||||
generated_server_marshallers.c \
|
|
||||||
generated_server_marshallers.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
BUILT_SOURCES = $(CLIENT_MARSHALLERS) $(SERVER_MARSHALLERS)
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libspice-common.la libspice-common-server.la libspice-common-client.la
|
|
||||||
libspice_common_la_SOURCES = \
|
libspice_common_la_SOURCES = \
|
||||||
agent.c \
|
bitops.h \
|
||||||
agent.h \
|
|
||||||
backtrace.c \
|
|
||||||
backtrace.h \
|
|
||||||
canvas_utils.c \
|
canvas_utils.c \
|
||||||
canvas_utils.h \
|
canvas_utils.h \
|
||||||
demarshallers.h \
|
|
||||||
draw.h \
|
draw.h \
|
||||||
lines.c \
|
lines.c \
|
||||||
lines.h \
|
lines.h \
|
||||||
log.c \
|
|
||||||
log.h \
|
|
||||||
lz.c \
|
lz.c \
|
||||||
lz.h \
|
lz.h \
|
||||||
lz_common.h \
|
lz_common.h \
|
||||||
lz_config.h \
|
lz_config.h \
|
||||||
macros.h \
|
|
||||||
marshaller.c \
|
marshaller.c \
|
||||||
marshaller.h \
|
marshaller.h \
|
||||||
mem.c \
|
mem.c \
|
||||||
mem.h \
|
mem.h \
|
||||||
messages.h \
|
messages.h \
|
||||||
|
mutex.h \
|
||||||
pixman_utils.c \
|
pixman_utils.c \
|
||||||
pixman_utils.h \
|
pixman_utils.h \
|
||||||
quic.c \
|
quic.c \
|
||||||
@ -50,112 +33,44 @@ libspice_common_la_SOURCES = \
|
|||||||
ring.h \
|
ring.h \
|
||||||
rop3.c \
|
rop3.c \
|
||||||
rop3.h \
|
rop3.h \
|
||||||
snd_codec.c \
|
spice_common.h \
|
||||||
snd_codec.h \
|
ssl_verify.c \
|
||||||
udev.c \
|
ssl_verify.h \
|
||||||
udev.h \
|
backtrace.c \
|
||||||
utils.c \
|
backtrace.h \
|
||||||
utils.h \
|
|
||||||
verify.h \
|
|
||||||
recorder.h \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
if ENABLE_RECORDER
|
if SUPPORT_GL
|
||||||
libspice_common_la_SOURCES += \
|
libspice_common_la_SOURCES += \
|
||||||
recorder/recorder.c \
|
gl_utils.h \
|
||||||
recorder/recorder.h \
|
glc.h \
|
||||||
recorder/recorder_ring.c \
|
glc.c \
|
||||||
recorder/recorder_ring.h \
|
ogl_ctx.h \
|
||||||
|
ogl_ctx.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ENABLE_AGENT_INTERFACE
|
INCLUDES = \
|
||||||
libspice_common_la_SOURCES += \
|
$(GL_CFLAGS) \
|
||||||
agent_interface.c \
|
$(PIXMAN_CFLAGS) \
|
||||||
agent_interface.h \
|
|
||||||
$(NULL)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# These 2 files are not build as part of spice-common
|
|
||||||
# build system, but modules using spice-common will build
|
|
||||||
# them with the appropriate options. We need to let automake
|
|
||||||
# know that these are source files so that it can properly
|
|
||||||
# track these files dependencies
|
|
||||||
EXTRA_libspice_common_la_SOURCES = \
|
|
||||||
sw_canvas.c \
|
|
||||||
sw_canvas.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
libspice_common_client_la_SOURCES = \
|
|
||||||
client_marshallers.h \
|
|
||||||
ssl_verify.c \
|
|
||||||
ssl_verify.h \
|
|
||||||
$(CLIENT_MARSHALLERS) \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
libspice_common_client_la_LIBADD = \
|
|
||||||
$(GIO2_LIBS) \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
libspice_common_server_la_SOURCES = \
|
|
||||||
$(SERVER_MARSHALLERS) \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
AM_CPPFLAGS = \
|
|
||||||
-I$(top_srcdir) \
|
|
||||||
-I$(top_builddir) \
|
|
||||||
$(SPICE_COMMON_CFLAGS) \
|
|
||||||
$(PROTOCOL_CFLAGS) \
|
$(PROTOCOL_CFLAGS) \
|
||||||
|
$(VISIBILITY_HIDDEN_CFLAGS) \
|
||||||
|
$(WARN_CFLAGS) \
|
||||||
|
-std=gnu99 \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
libspice_common_la_LIBADD = \
|
|
||||||
$(SPICE_COMMON_LIBS) \
|
|
||||||
$(UDEV_LIBS) \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
MARSHALLERS_DEPS = \
|
|
||||||
$(top_srcdir)/python_modules/__init__.py \
|
|
||||||
$(top_srcdir)/python_modules/codegen.py \
|
|
||||||
$(top_srcdir)/python_modules/demarshal.py \
|
|
||||||
$(top_srcdir)/python_modules/marshal.py \
|
|
||||||
$(top_srcdir)/python_modules/ptypes.py \
|
|
||||||
$(top_srcdir)/python_modules/spice_parser.py \
|
|
||||||
$(top_srcdir)/spice_codegen.py \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
# Note despite being autogenerated these are not part of CLEANFILES, they are
|
|
||||||
# actually a part of EXTRA_DIST, to avoid the need for pyparser by end users
|
|
||||||
generated_client_demarshallers.c generated_messages.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
|
|
||||||
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common/messages.h \
|
|
||||||
--generated-declaration-file generated_messages.h $< $@ >/dev/null
|
|
||||||
|
|
||||||
generated_client_marshallers.c generated_client_marshallers.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
|
|
||||||
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P --include common/client_marshallers.h --client \
|
|
||||||
--generate-header $< $@ >/dev/null
|
|
||||||
|
|
||||||
generated_server_demarshallers.c: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
|
|
||||||
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --server --include common/messages.h $< $@ >/dev/null
|
|
||||||
|
|
||||||
STRUCTS = -M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlend -M Composite
|
|
||||||
generated_server_marshallers.c generated_server_marshallers.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
|
|
||||||
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server --include common/messages.h \
|
|
||||||
--generate-header $< $@ >/dev/null
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
$(CLIENT_MARSHALLERS) \
|
|
||||||
$(SERVER_MARSHALLERS) \
|
|
||||||
generated_messages.h \
|
|
||||||
meson.build \
|
|
||||||
canvas_base.c \
|
canvas_base.c \
|
||||||
canvas_base.h \
|
canvas_base.h \
|
||||||
|
gdi_canvas.c \
|
||||||
|
gdi_canvas.h \
|
||||||
|
gl_canvas.c \
|
||||||
|
gl_canvas.h \
|
||||||
|
sw_canvas.c \
|
||||||
|
sw_canvas.h \
|
||||||
lz_compress_tmpl.c \
|
lz_compress_tmpl.c \
|
||||||
lz_decompress_tmpl.c \
|
lz_decompress_tmpl.c \
|
||||||
quic_family_tmpl.c \
|
quic_family_tmpl.c \
|
||||||
|
quic_rgb_tmpl.c \
|
||||||
quic_tmpl.c \
|
quic_tmpl.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
GITIGNOREFILES = \
|
|
||||||
generated_messages.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
-include $(top_srcdir)/git.mk
|
|
||||||
|
|||||||
361
common/agent.c
361
common/agent.c
@ -1,361 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2020 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include "agent.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Windows is always little endian
|
|
||||||
# define FIX_ENDIAN16(x) (x) = (x)
|
|
||||||
# define FIX_ENDIAN32(x) (x) = (x)
|
|
||||||
# define FIX_ENDIAN64(x) (x) = (x)
|
|
||||||
#else
|
|
||||||
# include <glib.h>
|
|
||||||
# define FIX_ENDIAN16(x) (x) = GUINT16_FROM_LE(x)
|
|
||||||
# define FIX_ENDIAN32(x) (x) = GUINT32_FROM_LE(x)
|
|
||||||
# define FIX_ENDIAN64(x) (x) = GUINT64_FROM_LE(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <spice/start-packed.h>
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
uint16_t v;
|
|
||||||
} uint16_unaligned_t;
|
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
uint32_t v;
|
|
||||||
} uint32_unaligned_t;
|
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
uint64_t v;
|
|
||||||
} uint64_unaligned_t;
|
|
||||||
#include <spice/end-packed.h>
|
|
||||||
|
|
||||||
static const int agent_message_min_size[] =
|
|
||||||
{
|
|
||||||
-1, /* Does not exist */
|
|
||||||
sizeof(VDAgentMouseState), /* VD_AGENT_MOUSE_STATE */
|
|
||||||
sizeof(VDAgentMonitorsConfig), /* VD_AGENT_MONITORS_CONFIG */
|
|
||||||
sizeof(VDAgentReply), /* VD_AGENT_REPLY */
|
|
||||||
sizeof(VDAgentClipboard), /* VD_AGENT_CLIPBOARD */
|
|
||||||
sizeof(VDAgentDisplayConfig), /* VD_AGENT_DISPLAY_CONFIG */
|
|
||||||
sizeof(VDAgentAnnounceCapabilities), /* VD_AGENT_ANNOUNCE_CAPABILITIES */
|
|
||||||
sizeof(VDAgentClipboardGrab), /* VD_AGENT_CLIPBOARD_GRAB */
|
|
||||||
sizeof(VDAgentClipboardRequest), /* VD_AGENT_CLIPBOARD_REQUEST */
|
|
||||||
sizeof(VDAgentClipboardRelease), /* VD_AGENT_CLIPBOARD_RELEASE */
|
|
||||||
sizeof(VDAgentFileXferStartMessage), /* VD_AGENT_FILE_XFER_START */
|
|
||||||
sizeof(VDAgentFileXferStatusMessage), /* VD_AGENT_FILE_XFER_STATUS */
|
|
||||||
sizeof(VDAgentFileXferDataMessage), /* VD_AGENT_FILE_XFER_DATA */
|
|
||||||
0, /* VD_AGENT_CLIENT_DISCONNECTED */
|
|
||||||
sizeof(VDAgentMaxClipboard), /* VD_AGENT_MAX_CLIPBOARD */
|
|
||||||
sizeof(VDAgentAudioVolumeSync), /* VD_AGENT_AUDIO_VOLUME_SYNC */
|
|
||||||
sizeof(VDAgentGraphicsDeviceInfo), /* VD_AGENT_GRAPHICS_DEVICE_INFO */
|
|
||||||
};
|
|
||||||
|
|
||||||
static AgentCheckResult
|
|
||||||
agent_message_check_size(const VDAgentMessage *message_header,
|
|
||||||
const uint32_t *capabilities, uint32_t capabilities_size)
|
|
||||||
{
|
|
||||||
if (message_header->protocol != VD_AGENT_PROTOCOL) {
|
|
||||||
return AGENT_CHECK_WRONG_PROTOCOL_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message_header->type >= SPICE_N_ELEMENTS(agent_message_min_size) ||
|
|
||||||
agent_message_min_size[message_header->type] < 0) {
|
|
||||||
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t min_size = agent_message_min_size[message_header->type];
|
|
||||||
|
|
||||||
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
|
||||||
VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
|
|
||||||
switch (message_header->type) {
|
|
||||||
case VD_AGENT_CLIPBOARD_GRAB:
|
|
||||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
|
||||||
case VD_AGENT_CLIPBOARD:
|
|
||||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
|
||||||
min_size += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
|
||||||
VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)
|
|
||||||
&& message_header->type == VD_AGENT_CLIPBOARD_GRAB) {
|
|
||||||
min_size += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message_header->type) {
|
|
||||||
case VD_AGENT_MONITORS_CONFIG:
|
|
||||||
case VD_AGENT_FILE_XFER_START:
|
|
||||||
case VD_AGENT_FILE_XFER_DATA:
|
|
||||||
case VD_AGENT_CLIPBOARD:
|
|
||||||
case VD_AGENT_CLIPBOARD_GRAB:
|
|
||||||
case VD_AGENT_AUDIO_VOLUME_SYNC:
|
|
||||||
case VD_AGENT_ANNOUNCE_CAPABILITIES:
|
|
||||||
case VD_AGENT_GRAPHICS_DEVICE_INFO:
|
|
||||||
case VD_AGENT_FILE_XFER_STATUS:
|
|
||||||
if (message_header->size < min_size) {
|
|
||||||
return AGENT_CHECK_INVALID_SIZE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VD_AGENT_MOUSE_STATE:
|
|
||||||
case VD_AGENT_DISPLAY_CONFIG:
|
|
||||||
case VD_AGENT_REPLY:
|
|
||||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
|
||||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
|
||||||
case VD_AGENT_MAX_CLIPBOARD:
|
|
||||||
case VD_AGENT_CLIENT_DISCONNECTED:
|
|
||||||
if (message_header->size != min_size) {
|
|
||||||
return AGENT_CHECK_INVALID_SIZE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
|
||||||
}
|
|
||||||
return AGENT_CHECK_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uint16_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
uint16_unaligned_t *msg = (uint16_unaligned_t *)(_msg + offset);
|
|
||||||
|
|
||||||
/* size % 2 should be 0 - extra bytes are ignored */
|
|
||||||
for (i = 0; i < size / 2; i++) {
|
|
||||||
FIX_ENDIAN16(msg[i].v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uint32_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
uint32_unaligned_t *msg = (uint32_unaligned_t *)(_msg + offset);
|
|
||||||
|
|
||||||
/* size % 4 should be 0 - extra bytes are ignored */
|
|
||||||
for (i = 0; i < size / 4; i++) {
|
|
||||||
FIX_ENDIAN32(msg[i].v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
agent_message_clipboard_from_le(const VDAgentMessage *message_header, uint8_t *data,
|
|
||||||
const uint32_t *capabilities, uint32_t capabilities_size)
|
|
||||||
{
|
|
||||||
size_t min_size = agent_message_min_size[message_header->type];
|
|
||||||
uint32_unaligned_t *data_type = (uint32_unaligned_t *) data;
|
|
||||||
|
|
||||||
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
|
||||||
VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
|
|
||||||
min_size += 4;
|
|
||||||
data_type++;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message_header->type) {
|
|
||||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
|
||||||
case VD_AGENT_CLIPBOARD:
|
|
||||||
FIX_ENDIAN32(data_type->v);
|
|
||||||
break;
|
|
||||||
case VD_AGENT_CLIPBOARD_GRAB:
|
|
||||||
uint32_from_le(data, message_header->size - min_size, min_size);
|
|
||||||
break;
|
|
||||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
|
||||||
// empty
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
agent_message_file_xfer_from_le(const VDAgentMessage *message_header, uint8_t *data)
|
|
||||||
{
|
|
||||||
uint32_unaligned_t *id = (uint32_unaligned_t *)data;
|
|
||||||
FIX_ENDIAN32(id->v);
|
|
||||||
id++; // result
|
|
||||||
|
|
||||||
switch (message_header->type) {
|
|
||||||
case VD_AGENT_FILE_XFER_DATA: {
|
|
||||||
VDAgentFileXferDataMessage *msg = (VDAgentFileXferDataMessage *) data;
|
|
||||||
FIX_ENDIAN64(msg->size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VD_AGENT_FILE_XFER_STATUS: {
|
|
||||||
VDAgentFileXferStatusMessage *msg = (VDAgentFileXferStatusMessage *) data;
|
|
||||||
FIX_ENDIAN32(msg->result);
|
|
||||||
// from client/server we don't expect any detail
|
|
||||||
switch (msg->result) {
|
|
||||||
case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE:
|
|
||||||
if (message_header->size >= sizeof(VDAgentFileXferStatusMessage) +
|
|
||||||
sizeof(VDAgentFileXferStatusNotEnoughSpace)) {
|
|
||||||
VDAgentFileXferStatusNotEnoughSpace *err =
|
|
||||||
(VDAgentFileXferStatusNotEnoughSpace*) msg->data;
|
|
||||||
FIX_ENDIAN64(err->disk_free_space);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VD_AGENT_FILE_XFER_STATUS_ERROR:
|
|
||||||
if (message_header->size >= sizeof(VDAgentFileXferStatusMessage) +
|
|
||||||
sizeof(VDAgentFileXferStatusError)) {
|
|
||||||
VDAgentFileXferStatusError *err =
|
|
||||||
(VDAgentFileXferStatusError *) msg->data;
|
|
||||||
FIX_ENDIAN32(err->error_code);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static AgentCheckResult
|
|
||||||
agent_message_graphics_device_info_check_from_le(const VDAgentMessage *message_header,
|
|
||||||
uint8_t *data)
|
|
||||||
{
|
|
||||||
uint8_t *const end = data + message_header->size;
|
|
||||||
uint32_unaligned_t *u32 = (uint32_unaligned_t *) data;
|
|
||||||
FIX_ENDIAN32(u32->v);
|
|
||||||
const uint32_t count = u32->v;
|
|
||||||
data += 4;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
if ((size_t) (end - data) < sizeof(VDAgentDeviceDisplayInfo)) {
|
|
||||||
return AGENT_CHECK_TRUNCATED;
|
|
||||||
}
|
|
||||||
uint32_from_le(data, sizeof(VDAgentDeviceDisplayInfo), 0);
|
|
||||||
VDAgentDeviceDisplayInfo *info = (VDAgentDeviceDisplayInfo *) data;
|
|
||||||
data += sizeof(VDAgentDeviceDisplayInfo);
|
|
||||||
if (!info->device_address_len) {
|
|
||||||
return AGENT_CHECK_INVALID_DATA;
|
|
||||||
}
|
|
||||||
if ((size_t) (end - data) < info->device_address_len) {
|
|
||||||
return AGENT_CHECK_TRUNCATED;
|
|
||||||
}
|
|
||||||
info->device_address[info->device_address_len - 1] = 0;
|
|
||||||
data += info->device_address_len;
|
|
||||||
}
|
|
||||||
return AGENT_CHECK_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AgentCheckResult
|
|
||||||
agent_message_monitors_config_from_le(const VDAgentMessage *message_header, uint8_t *message)
|
|
||||||
{
|
|
||||||
uint32_from_le(message, sizeof(VDAgentMonitorsConfig), 0);
|
|
||||||
VDAgentMonitorsConfig *vdata = (VDAgentMonitorsConfig*) message;
|
|
||||||
vdata->flags &= VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS|
|
|
||||||
VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE;
|
|
||||||
size_t element_size = sizeof(vdata->monitors[0]);
|
|
||||||
if ((vdata->flags & VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE) != 0) {
|
|
||||||
element_size += sizeof(VDAgentMonitorMM);
|
|
||||||
}
|
|
||||||
const size_t max_monitors =
|
|
||||||
(message_header->size - sizeof(*vdata)) / element_size;
|
|
||||||
if (vdata->num_of_monitors > max_monitors) {
|
|
||||||
return AGENT_CHECK_TRUNCATED;
|
|
||||||
}
|
|
||||||
uint32_from_le(message, sizeof(vdata->monitors[0]) * vdata->num_of_monitors,
|
|
||||||
sizeof(*vdata));
|
|
||||||
if ((vdata->flags & VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE) != 0) {
|
|
||||||
uint16_from_le(message, sizeof(VDAgentMonitorMM) * vdata->num_of_monitors,
|
|
||||||
sizeof(*vdata) + sizeof(vdata->monitors[0]) * vdata->num_of_monitors);
|
|
||||||
}
|
|
||||||
return AGENT_CHECK_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
AgentCheckResult
|
|
||||||
agent_check_message(const VDAgentMessage *message_header, uint8_t *message,
|
|
||||||
const uint32_t *capabilities, uint32_t capabilities_size)
|
|
||||||
{
|
|
||||||
AgentCheckResult res;
|
|
||||||
|
|
||||||
res = agent_message_check_size(message_header, capabilities, capabilities_size);
|
|
||||||
if (res != AGENT_CHECK_NO_ERROR) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message_header->type) {
|
|
||||||
case VD_AGENT_MOUSE_STATE:
|
|
||||||
uint32_from_le(message, 3 * sizeof(uint32_t), 0);
|
|
||||||
break;
|
|
||||||
case VD_AGENT_REPLY:
|
|
||||||
case VD_AGENT_DISPLAY_CONFIG:
|
|
||||||
case VD_AGENT_MAX_CLIPBOARD:
|
|
||||||
case VD_AGENT_ANNOUNCE_CAPABILITIES:
|
|
||||||
uint32_from_le(message, message_header->size, 0);
|
|
||||||
break;
|
|
||||||
case VD_AGENT_MONITORS_CONFIG:
|
|
||||||
return agent_message_monitors_config_from_le(message_header, message);
|
|
||||||
|
|
||||||
case VD_AGENT_CLIPBOARD:
|
|
||||||
case VD_AGENT_CLIPBOARD_GRAB:
|
|
||||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
|
||||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
|
||||||
agent_message_clipboard_from_le(message_header, message,
|
|
||||||
capabilities, capabilities_size);
|
|
||||||
break;
|
|
||||||
case VD_AGENT_FILE_XFER_START:
|
|
||||||
case VD_AGENT_FILE_XFER_STATUS:
|
|
||||||
case VD_AGENT_FILE_XFER_DATA:
|
|
||||||
agent_message_file_xfer_from_le(message_header, message);
|
|
||||||
break;
|
|
||||||
case VD_AGENT_CLIENT_DISCONNECTED:
|
|
||||||
break;
|
|
||||||
case VD_AGENT_GRAPHICS_DEVICE_INFO:
|
|
||||||
return agent_message_graphics_device_info_check_from_le(message_header, message);
|
|
||||||
|
|
||||||
case VD_AGENT_AUDIO_VOLUME_SYNC: {
|
|
||||||
VDAgentAudioVolumeSync *vdata = (VDAgentAudioVolumeSync *)message;
|
|
||||||
const size_t max_channels =
|
|
||||||
(message_header->size - sizeof(*vdata)) / sizeof(vdata->volume[0]);
|
|
||||||
if (vdata->nchannels > max_channels) {
|
|
||||||
return AGENT_CHECK_TRUNCATED;
|
|
||||||
}
|
|
||||||
uint16_from_le(message, message_header->size - sizeof(*vdata), sizeof(*vdata));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
|
||||||
}
|
|
||||||
return AGENT_CHECK_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
agent_prepare_filexfer_status(AgentFileXferStatusMessageFull *status, size_t *status_size,
|
|
||||||
const uint32_t *capabilities, uint32_t capabilities_size)
|
|
||||||
{
|
|
||||||
if (*status_size < sizeof(status->common)) {
|
|
||||||
*status_size = sizeof(status->common);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there are details but no cap for detail remove it
|
|
||||||
if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
|
||||||
VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS)) {
|
|
||||||
*status_size = sizeof(status->common);
|
|
||||||
|
|
||||||
// if detail cap is not provided and error > threshold set to error
|
|
||||||
if (status->common.result >= VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE) {
|
|
||||||
status->common.result = VD_AGENT_FILE_XFER_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix endian
|
|
||||||
switch (status->common.result) {
|
|
||||||
case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE:
|
|
||||||
FIX_ENDIAN64(status->not_enough_space.disk_free_space);
|
|
||||||
break;
|
|
||||||
case VD_AGENT_FILE_XFER_STATUS_ERROR:
|
|
||||||
FIX_ENDIAN32(status->error.error_code);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// header should be done last
|
|
||||||
FIX_ENDIAN32(status->common.id);
|
|
||||||
FIX_ENDIAN32(status->common.result);
|
|
||||||
}
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2020 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <spice/macros.h>
|
|
||||||
#include <spice/vd_agent.h>
|
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
|
||||||
|
|
||||||
#include <spice/start-packed.h>
|
|
||||||
|
|
||||||
/* This helper macro is to define a structure in a way compatible with
|
|
||||||
* Microsoft compiler */
|
|
||||||
#define SPICE_INNER_FIELD_STATUS_ERROR(type, name) \
|
|
||||||
struct SPICE_ATTR_PACKED { \
|
|
||||||
char common_ ## name[sizeof(VDAgentFileXferStatusMessage)]; \
|
|
||||||
type name; \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure to fill with transfer status.
|
|
||||||
* Fill as much details as you can and call agent_prepare_filexfer_status
|
|
||||||
* before sending to adjust for capabilities and endianness.
|
|
||||||
* If any detail are filled the status_size passed to agent_prepare_filexfer_status
|
|
||||||
* should be updated.
|
|
||||||
*/
|
|
||||||
typedef union SPICE_ATTR_PACKED AgentFileXferStatusMessageFull {
|
|
||||||
VDAgentFileXferStatusMessage common;
|
|
||||||
SPICE_INNER_FIELD_STATUS_ERROR(VDAgentFileXferStatusNotEnoughSpace, not_enough_space);
|
|
||||||
SPICE_INNER_FIELD_STATUS_ERROR(VDAgentFileXferStatusError, error);
|
|
||||||
} AgentFileXferStatusMessageFull;
|
|
||||||
|
|
||||||
#undef SPICE_INNER_FIELD_STATUS_ERROR
|
|
||||||
|
|
||||||
#include <spice/end-packed.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare AgentFileXferStatusMessageFull to
|
|
||||||
* be sent to network.
|
|
||||||
* Avoid protocol incompatibilities and endian issues
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
agent_prepare_filexfer_status(AgentFileXferStatusMessageFull *status, size_t *status_size,
|
|
||||||
const uint32_t *capabilities, uint32_t capabilities_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Possible results checking a message.
|
|
||||||
* Beside AGENT_CHECK_NO_ERROR all other conditions are errors.
|
|
||||||
*/
|
|
||||||
typedef enum AgentCheckResult {
|
|
||||||
AGENT_CHECK_NO_ERROR,
|
|
||||||
AGENT_CHECK_WRONG_PROTOCOL_VERSION,
|
|
||||||
AGENT_CHECK_UNKNOWN_MESSAGE,
|
|
||||||
AGENT_CHECK_INVALID_SIZE,
|
|
||||||
AGENT_CHECK_TRUNCATED,
|
|
||||||
AGENT_CHECK_INVALID_DATA,
|
|
||||||
} AgentCheckResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check message from network and fix endianness
|
|
||||||
* Returns AGENT_CHECK_NO_ERROR if message is valid.
|
|
||||||
* message buffer size should be message_header->size.
|
|
||||||
*/
|
|
||||||
AgentCheckResult
|
|
||||||
agent_check_message(const VDAgentMessage *message_header, uint8_t *message,
|
|
||||||
const uint32_t *capabilities, uint32_t capabilities_size);
|
|
||||||
|
|
||||||
SPICE_END_DECLS
|
|
||||||
@ -1,510 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2019 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <sys/eventfd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <poll.h>
|
|
||||||
|
|
||||||
#include <common/agent_interface.h>
|
|
||||||
|
|
||||||
typedef struct sockaddr SA;
|
|
||||||
|
|
||||||
static GThread *recorder_comm_thr;
|
|
||||||
static bool agent_terminated = false;
|
|
||||||
static int terminate_efd = -1;
|
|
||||||
static FILE *communication_f = NULL;
|
|
||||||
|
|
||||||
#define NB_MAX_RECORDERS 16
|
|
||||||
static recorder_info *recorders[NB_MAX_RECORDERS];
|
|
||||||
static uint32_t nb_recorders = 0;
|
|
||||||
|
|
||||||
static forward_quality_cb_t forward_quality_cb;
|
|
||||||
static void *forward_quality_cb_data;
|
|
||||||
|
|
||||||
static on_connect_cb_t on_connect_cb;
|
|
||||||
static void *on_connect_cb_data;
|
|
||||||
|
|
||||||
static uintptr_t recorder_tick(void);
|
|
||||||
|
|
||||||
#ifndef RECORDER_HZ
|
|
||||||
#define RECORDER_HZ 1000000
|
|
||||||
#endif // RECORDER_HZ
|
|
||||||
|
|
||||||
static GMutex mutex_socket;
|
|
||||||
|
|
||||||
static int agent_initialize_communication(int socket)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
int ret = -1;
|
|
||||||
FILE *socket_f;
|
|
||||||
|
|
||||||
g_mutex_lock(&mutex_socket);
|
|
||||||
|
|
||||||
if (communication_f != NULL) {
|
|
||||||
g_warning("A client is already connected, rejecting the connection.");
|
|
||||||
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket_f = fdopen(socket, "w+b");
|
|
||||||
|
|
||||||
fprintf(socket_f, "Recorders: ");
|
|
||||||
for (i = 0; i < nb_recorders; i++) {
|
|
||||||
g_debug("Sending %s", recorders[i]->name);
|
|
||||||
fprintf(socket_f, "%s;", recorders[i]->name);
|
|
||||||
}
|
|
||||||
fprintf(socket_f, "\n");
|
|
||||||
fflush(socket_f);
|
|
||||||
|
|
||||||
for (i = 0; i < nb_recorders; i++) {
|
|
||||||
char enable;
|
|
||||||
|
|
||||||
if (read(socket, &enable, sizeof(enable)) != sizeof(enable)) {
|
|
||||||
g_warning("Invalid read on the client socket");
|
|
||||||
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (enable != '0' && enable != '1') {
|
|
||||||
g_critical("Invalid enable-value received for recorder '%s': %u",
|
|
||||||
recorders[i]->name, enable);
|
|
||||||
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enable == '0') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
recorders[i]->trace = 1;
|
|
||||||
g_info("Enable recorder '%s'", recorders[i]->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (on_connect_cb && on_connect_cb(on_connect_cb_data)) {
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
communication_f = socket_f;
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
unlock:
|
|
||||||
g_mutex_unlock(&mutex_socket);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void agent_finalize_communication(int socket)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
g_info("Communication socket closed.");
|
|
||||||
|
|
||||||
g_mutex_lock(&mutex_socket);
|
|
||||||
g_assert(socket == fileno(communication_f));
|
|
||||||
|
|
||||||
fclose(communication_f);
|
|
||||||
communication_f = NULL;
|
|
||||||
|
|
||||||
for (i = 0; i < nb_recorders; i++) {
|
|
||||||
recorders[i]->trace = 0;
|
|
||||||
}
|
|
||||||
g_mutex_unlock(&mutex_socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void forward_quality(const char *quality)
|
|
||||||
{
|
|
||||||
if (!forward_quality_cb) {
|
|
||||||
g_warning("Quality: No callback set, dropping the message (%s).", quality);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_info("Quality: Forwarding '%s'", quality);
|
|
||||||
|
|
||||||
forward_quality_cb(forward_quality_cb_data, quality);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int agent_process_communication(int socket)
|
|
||||||
{
|
|
||||||
static char msg_in[128];
|
|
||||||
|
|
||||||
static long unsigned int len = 0;
|
|
||||||
|
|
||||||
g_assert(socket == fileno(communication_f));
|
|
||||||
|
|
||||||
int nbytes = read(socket, msg_in + len, 1);
|
|
||||||
|
|
||||||
if (nbytes < 0 && errno == EINTR) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes <= 0) {
|
|
||||||
agent_finalize_communication(socket);
|
|
||||||
return -1; // socket closed
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg_in[len] == '\0') {
|
|
||||||
// process quality indicator
|
|
||||||
forward_quality(msg_in);
|
|
||||||
len = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
len += nbytes;
|
|
||||||
|
|
||||||
if (len >= sizeof(msg_in) - 1) {
|
|
||||||
msg_in[sizeof(msg_in) - 1] = '\0';
|
|
||||||
g_warning("Invalid message received (too long?): %s", msg_in);
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int make_socket(guint port)
|
|
||||||
{
|
|
||||||
struct sockaddr_in servaddr;
|
|
||||||
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
|
|
||||||
if (listen_socket == -1) {
|
|
||||||
g_critical("socket creation failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int enable = 1;
|
|
||||||
if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
|
|
||||||
g_critical("setsockopt(SO_REUSEADDR) failed");
|
|
||||||
close(listen_socket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&servaddr, 0, sizeof(servaddr));
|
|
||||||
|
|
||||||
servaddr.sin_family = AF_INET;
|
|
||||||
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
servaddr.sin_port = htons(port);
|
|
||||||
|
|
||||||
if (bind(listen_socket, (SA *) &servaddr, sizeof(servaddr)) != 0) {
|
|
||||||
g_critical("socket bind failed");
|
|
||||||
close(listen_socket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return listen_socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gpointer handle_communications(gpointer user_data)
|
|
||||||
{
|
|
||||||
struct pollfd fds[3];
|
|
||||||
int nb_fd = 0;
|
|
||||||
int listen_socket;
|
|
||||||
int i;
|
|
||||||
guint port = GPOINTER_TO_UINT(user_data);
|
|
||||||
|
|
||||||
listen_socket = make_socket(port);
|
|
||||||
if (listen_socket < 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug("Listening!");
|
|
||||||
|
|
||||||
if ((listen(listen_socket, 1)) != 0) {
|
|
||||||
g_critical("listen failed: %m");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fds[0].fd = terminate_efd;
|
|
||||||
fds[0].events = POLLIN;
|
|
||||||
fds[1].fd = listen_socket;
|
|
||||||
fds[1].events = POLLIN;
|
|
||||||
nb_fd = 2;
|
|
||||||
|
|
||||||
while (!agent_terminated) {
|
|
||||||
|
|
||||||
/* Block until input arrives on one or more active sockets. */
|
|
||||||
int ret = poll(fds, nb_fd, -1);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
g_critical("poll failed: %m");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Service all the sockets with input pending. */
|
|
||||||
for (i = 0; i < nb_fd; i++) {
|
|
||||||
int fd = fds[i].fd;
|
|
||||||
if (fd == terminate_efd) {
|
|
||||||
if (fds[i].revents & POLLIN) {
|
|
||||||
g_assert(agent_terminated);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (fd == listen_socket) {
|
|
||||||
if (fds[i].revents & ~POLLIN) {
|
|
||||||
g_critical("server socket closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!(fds[i].revents & POLLIN)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Connection request on original socket. */
|
|
||||||
int new_fd = accept(listen_socket, NULL, NULL);
|
|
||||||
|
|
||||||
if (new_fd < 0) {
|
|
||||||
g_critical("accept failed: %m");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nb_fd == 3) {
|
|
||||||
close(new_fd);
|
|
||||||
g_warning("Too many clients accepted ...");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug("Agent Interface: client connected!");
|
|
||||||
|
|
||||||
if (agent_initialize_communication(new_fd)) {
|
|
||||||
close(new_fd);
|
|
||||||
g_warning("Initialization failed ...");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fds[nb_fd].fd = new_fd;
|
|
||||||
fds[nb_fd].events = POLLIN;
|
|
||||||
nb_fd++;
|
|
||||||
|
|
||||||
/* fds array modified, restart the poll. */
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (!(fds[i].revents & POLLIN)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Data arriving on an already-connected socket. */
|
|
||||||
if (agent_process_communication(fd) < 0) {
|
|
||||||
nb_fd--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close(terminate_efd);
|
|
||||||
close(listen_socket);
|
|
||||||
|
|
||||||
g_info("Agent interface thread: bye!");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void recorder_deregister(void);
|
|
||||||
|
|
||||||
static void recorder_initialization(unsigned int port)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
terminate_efd = eventfd(0, 0);
|
|
||||||
if (terminate_efd == -1) {
|
|
||||||
g_critical("eventfd failed: %m");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
recorder_comm_thr = g_thread_try_new("smart_agent_interface",
|
|
||||||
handle_communications,
|
|
||||||
GUINT_TO_POINTER((guint) port), &error);
|
|
||||||
if (error) {
|
|
||||||
g_assert(!recorder_comm_thr);
|
|
||||||
g_critical("Error: Could not start the agent interface thread: %s", error->message);
|
|
||||||
g_error_free(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
atexit(recorder_deregister);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void recorder_interrupt_communications(void)
|
|
||||||
{
|
|
||||||
agent_terminated = true;
|
|
||||||
|
|
||||||
uint64_t msg = 1;
|
|
||||||
ssize_t s = write(terminate_efd, &msg, sizeof(uint64_t));
|
|
||||||
|
|
||||||
if (s != sizeof(uint64_t)) {
|
|
||||||
g_warning("failed to send recorder thread termination event: %m");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void recorder_deregister(void)
|
|
||||||
{
|
|
||||||
if (recorder_comm_thr) {
|
|
||||||
recorder_interrupt_communications();
|
|
||||||
g_thread_join(recorder_comm_thr);
|
|
||||||
recorder_comm_thr = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void recorder_activate(recorder_info *recorder)
|
|
||||||
{
|
|
||||||
if (nb_recorders >= NB_MAX_RECORDERS) {
|
|
||||||
g_critical("Too many recorders configured (nb max: %d)", NB_MAX_RECORDERS);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
recorders[nb_recorders] = recorder;
|
|
||||||
nb_recorders++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_send_entry(FILE *dest, recorder_info *info, recorder_entry *entry, va_list args)
|
|
||||||
{
|
|
||||||
fprintf(dest, "Name: %s\nFunction: %s\nTime: %lu\n",
|
|
||||||
info->name, entry->where, entry->timestamp);
|
|
||||||
|
|
||||||
vfprintf(dest, entry->format, args);
|
|
||||||
fprintf(dest, "\n\n");
|
|
||||||
|
|
||||||
fflush(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void recorder_trace_entry(recorder_info *info, recorder_entry *entry, ...)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Show a recorder entry when a trace is enabled
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
if (strchr(entry->format, '\n') != NULL) {
|
|
||||||
g_critical("Agent records cannot contain '\n' char ... (%s)", entry->where);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send info/entry to the socket
|
|
||||||
g_mutex_lock(&mutex_socket);
|
|
||||||
|
|
||||||
if (communication_f == NULL) {
|
|
||||||
g_mutex_unlock(&mutex_socket);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_start(args, entry);
|
|
||||||
do_send_entry(communication_f, info, entry, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
if (g_strcmp0(g_getenv("SPICE_AGENT_LOG_RECORDS"), "1") == 0) {
|
|
||||||
va_start(args, entry);
|
|
||||||
do_send_entry(stderr, info, entry, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_mutex_unlock(&mutex_socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void agent_interface_start(unsigned int port)
|
|
||||||
{
|
|
||||||
g_info("Launch on port %u", port);
|
|
||||||
recorder_initialization(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data)
|
|
||||||
{
|
|
||||||
g_debug("Received forward_quality callback");
|
|
||||||
forward_quality_cb = cb;
|
|
||||||
forward_quality_cb_data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data)
|
|
||||||
{
|
|
||||||
g_debug("Received on_connect callback");
|
|
||||||
on_connect_cb = cb;
|
|
||||||
on_connect_cb_data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void recorder_append(recorder_info *rec,
|
|
||||||
const char *where,
|
|
||||||
const char *format,
|
|
||||||
uintptr_t a0,
|
|
||||||
uintptr_t a1,
|
|
||||||
uintptr_t a2,
|
|
||||||
uintptr_t a3)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Enter a record entry in ring buffer with given set of args
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
recorder_entry entry;
|
|
||||||
|
|
||||||
if (!rec->trace) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.format = format;
|
|
||||||
entry.timestamp = recorder_tick();
|
|
||||||
entry.where = where;
|
|
||||||
|
|
||||||
recorder_trace_entry(rec, &entry, a0, a1, a2, a3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void recorder_append2(recorder_info *rec,
|
|
||||||
const char *where,
|
|
||||||
const char *format,
|
|
||||||
uintptr_t a0,
|
|
||||||
uintptr_t a1,
|
|
||||||
uintptr_t a2,
|
|
||||||
uintptr_t a3,
|
|
||||||
uintptr_t a4,
|
|
||||||
uintptr_t a5,
|
|
||||||
uintptr_t a6,
|
|
||||||
uintptr_t a7)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Enter a double record (up to 8 args)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
recorder_entry entry;
|
|
||||||
|
|
||||||
if (!rec->trace) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.format = format;
|
|
||||||
entry.timestamp = recorder_tick();
|
|
||||||
entry.where = where;
|
|
||||||
|
|
||||||
recorder_trace_entry(rec, &entry, a0, a1, a2, a3, a4, a5, a6, a7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Support functions
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static uintptr_t recorder_tick(void)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Return the "ticks" as stored in the recorder
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
struct timeval t;
|
|
||||||
|
|
||||||
gettimeofday(&t, NULL);
|
|
||||||
|
|
||||||
return t.tv_sec * RECORDER_HZ + t.tv_usec / (1000000 / RECORDER_HZ);
|
|
||||||
}
|
|
||||||
@ -1,564 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// *****************************************************************************
|
|
||||||
// This software is licensed under the GNU Lesser General Public License v2+
|
|
||||||
// (C) 2017-2019, Christophe de Dinechin <christophe@dinechin.org>
|
|
||||||
// *****************************************************************************
|
|
||||||
// This file was part of Recorder
|
|
||||||
//
|
|
||||||
// Recorder is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Recorder is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with Recorder, in a file named COPYING.
|
|
||||||
// If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
// *****************************************************************************
|
|
||||||
/* This file is based on Recorder's recorder.h file, that describes a general-
|
|
||||||
* purpose instrumentation interface. agent_interface.h is a trimmed-down
|
|
||||||
* version of it. */
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
recorder_dump_on_common_signals(unsigned add, unsigned remove)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Recorder data structures
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
typedef struct recorder_entry
|
|
||||||
/// ---------------------------------------------------------------------------
|
|
||||||
/// Entry in the flight recorder.
|
|
||||||
///----------------------------------------------------------------------------
|
|
||||||
/// Notice that the arguments are stored as "intptr_t" because that type
|
|
||||||
/// is guaranteed to be the same size as a pointer. This allows us to
|
|
||||||
/// properly align recorder entries to powers of 2 for efficiency.
|
|
||||||
/// Also read explanations of \ref _recorder_double and \ref _recorder_float
|
|
||||||
/// below regarding how to use floating-point with the recorder.
|
|
||||||
{
|
|
||||||
const char *format; ///< Printf-style format for record + file/line
|
|
||||||
uintptr_t timestamp; ///< Time at which record took place
|
|
||||||
const char *where; ///< Source code function
|
|
||||||
uintptr_t args[4]; ///< Four arguments, for a total of 8 fields
|
|
||||||
} recorder_entry;
|
|
||||||
|
|
||||||
|
|
||||||
/// A global counter indicating the order of entries across recorders.
|
|
||||||
/// this is incremented atomically for each record() call.
|
|
||||||
/// It must be exposed because all XYZ_record() implementations need to
|
|
||||||
/// touch the same shared variable in order to provide a global order.
|
|
||||||
extern uintptr_t recorder_order;
|
|
||||||
|
|
||||||
typedef struct recorder_info
|
|
||||||
///----------------------------------------------------------------------------
|
|
||||||
/// A linked list of the activated recorders
|
|
||||||
///----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
intptr_t trace; ///< Trace this recorder
|
|
||||||
const char * name; ///< Name of this parameter / recorder
|
|
||||||
const char * description;///< Description of what is recorded
|
|
||||||
recorder_entry data[0]; ///< Data for this recorder
|
|
||||||
} recorder_info;
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Adding data to a recorder
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
extern void recorder_append(recorder_info *rec,
|
|
||||||
const char *where,
|
|
||||||
const char *format,
|
|
||||||
uintptr_t a0,
|
|
||||||
uintptr_t a1,
|
|
||||||
uintptr_t a2,
|
|
||||||
uintptr_t a3);
|
|
||||||
extern void recorder_append2(recorder_info *rec,
|
|
||||||
const char *where,
|
|
||||||
const char *format,
|
|
||||||
uintptr_t a0,
|
|
||||||
uintptr_t a1,
|
|
||||||
uintptr_t a2,
|
|
||||||
uintptr_t a3,
|
|
||||||
uintptr_t a4,
|
|
||||||
uintptr_t a5,
|
|
||||||
uintptr_t a6,
|
|
||||||
uintptr_t a7);
|
|
||||||
extern void recorder_append3(recorder_info *rec,
|
|
||||||
const char *where,
|
|
||||||
const char *format,
|
|
||||||
uintptr_t a0,
|
|
||||||
uintptr_t a1,
|
|
||||||
uintptr_t a2,
|
|
||||||
uintptr_t a3,
|
|
||||||
uintptr_t a4,
|
|
||||||
uintptr_t a5,
|
|
||||||
uintptr_t a6,
|
|
||||||
uintptr_t a7,
|
|
||||||
uintptr_t a8,
|
|
||||||
uintptr_t a9,
|
|
||||||
uintptr_t a10,
|
|
||||||
uintptr_t a11);
|
|
||||||
|
|
||||||
/// Activate a recorder (during construction time)
|
|
||||||
extern void recorder_activate(recorder_info *recorder);
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Declaration of recorders and tweaks
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#define RECORDER_DECLARE(Name) \
|
|
||||||
/* ----------------------------------------------------------------*/ \
|
|
||||||
/* Declare a recorder with the given name (for use in headers) */ \
|
|
||||||
/* ----------------------------------------------------------------*/ \
|
|
||||||
extern recorder_info * const recorder_info_ptr_for_##Name; \
|
|
||||||
extern struct recorder_info_for_##Name recorder_info_for_##Name
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Definition of recorders and tweaks
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#define RECORDER(Name, Size, Info) RECORDER_DEFINE(Name,Size,Info)
|
|
||||||
|
|
||||||
#define RECORDER_DEFINE(Name, Size, Info) \
|
|
||||||
/*!----------------------------------------------------------------*/ \
|
|
||||||
/*! Define a recorder type with Size elements */ \
|
|
||||||
/*!----------------------------------------------------------------*/ \
|
|
||||||
/*! \param Name is the C name fo the recorder. \
|
|
||||||
*! \param Size is the number of entries in the circular buffer. \
|
|
||||||
*! \param Info is a description of the recorder for help. */ \
|
|
||||||
\
|
|
||||||
/* The entry in linked list for this type */ \
|
|
||||||
struct recorder_info_for_##Name \
|
|
||||||
{ \
|
|
||||||
recorder_info info; \
|
|
||||||
recorder_entry data[Size]; \
|
|
||||||
} \
|
|
||||||
recorder_info_for_##Name = \
|
|
||||||
{ \
|
|
||||||
{ \
|
|
||||||
0, #Name, Info, {} \
|
|
||||||
}, \
|
|
||||||
{} \
|
|
||||||
}; \
|
|
||||||
recorder_info * const recorder_info_ptr_for_##Name = \
|
|
||||||
&recorder_info_for_##Name.info; \
|
|
||||||
\
|
|
||||||
RECORDER_CONSTRUCTOR \
|
|
||||||
static void recorder_activate_##Name(void) \
|
|
||||||
/* ----------------------------------------------------------------*/ \
|
|
||||||
/* Activate recorder before entering main() */ \
|
|
||||||
/* ----------------------------------------------------------------*/ \
|
|
||||||
{ \
|
|
||||||
recorder_activate(RECORDER_INFO(Name)); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/* Purposefully generate compile error if macro not followed by ; */ \
|
|
||||||
extern void recorder_activate(recorder_info *recorder)
|
|
||||||
|
|
||||||
typedef struct SpiceDummyTweak {
|
|
||||||
intptr_t tweak_value;
|
|
||||||
} SpiceDummyTweak;
|
|
||||||
|
|
||||||
typedef struct SpiceEmptyStruct {
|
|
||||||
char dummy[0];
|
|
||||||
} SpiceEmptyStruct;
|
|
||||||
|
|
||||||
#define RECORDER_TWEAK_DECLARE(rec) \
|
|
||||||
extern const SpiceDummyTweak spice_recorder_tweak_ ## rec
|
|
||||||
|
|
||||||
#define RECORDER_TWEAK_DEFINE(rec, value, comment) \
|
|
||||||
const SpiceDummyTweak spice_recorder_tweak_ ## rec = { (value) }
|
|
||||||
|
|
||||||
#define RECORDER_TWEAK(rec) \
|
|
||||||
((spice_recorder_tweak_ ## rec).tweak_value)
|
|
||||||
|
|
||||||
#define RECORDER_TRACE(rec) \
|
|
||||||
(sizeof(struct recorder_info_for_ ## rec) != sizeof(SpiceEmptyStruct))
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Access to recorder and tweak info
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#define RECORDER_INFO(Name) (recorder_info_ptr_for_##Name)
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Recording stuff
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#define record(Name, ...) RECORD_MACRO(Name, __VA_ARGS__)
|
|
||||||
#define RECORD(Name,...) RECORD_MACRO(Name, __VA_ARGS__)
|
|
||||||
#define RECORD_MACRO(Name, ...) \
|
|
||||||
RECORD_(RECORD,RECORD_COUNT_(__VA_ARGS__),Name,__VA_ARGS__)
|
|
||||||
#define RECORD_(RECORD,RCOUNT,Name,...) \
|
|
||||||
RECORD__(RECORD,RCOUNT,Name,__VA_ARGS__)
|
|
||||||
#define RECORD__(RECORD,RCOUNT,Name,...) \
|
|
||||||
RECORD##RCOUNT(Name,__VA_ARGS__)
|
|
||||||
#define RECORD_COUNT_(...) RECORD_COUNT__(Dummy,##__VA_ARGS__,_X,_X,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,_0)
|
|
||||||
#define RECORD_COUNT__(Dummy,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_N,...) _N
|
|
||||||
|
|
||||||
#define RECORD_0(Name, Format) \
|
|
||||||
recorder_append(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, 0, 0, 0, 0)
|
|
||||||
#define RECORD_1(Name, Format, a) \
|
|
||||||
recorder_append(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), 0, 0, 0)
|
|
||||||
#define RECORD_2(Name, Format, a,b) \
|
|
||||||
recorder_append(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), 0, 0)
|
|
||||||
#define RECORD_3(Name, Format, a,b,c) \
|
|
||||||
recorder_append(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), 0)
|
|
||||||
#define RECORD_4(Name, Format, a,b,c,d) \
|
|
||||||
recorder_append(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d))
|
|
||||||
#define RECORD_5(Name, Format, a,b,c,d,e) \
|
|
||||||
recorder_append2(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d), \
|
|
||||||
RECORDER_ARG(e), 0, 0, 0)
|
|
||||||
#define RECORD_6(Name, Format, a,b,c,d,e,f) \
|
|
||||||
recorder_append2(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d), \
|
|
||||||
RECORDER_ARG(e), \
|
|
||||||
RECORDER_ARG(f), 0, 0)
|
|
||||||
#define RECORD_7(Name, Format, a,b,c,d,e,f,g) \
|
|
||||||
recorder_append2(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d), \
|
|
||||||
RECORDER_ARG(e), \
|
|
||||||
RECORDER_ARG(f), \
|
|
||||||
RECORDER_ARG(g), 0)
|
|
||||||
#define RECORD_8(Name, Format, a,b,c,d,e,f,g,h) \
|
|
||||||
recorder_append2(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d), \
|
|
||||||
RECORDER_ARG(e), \
|
|
||||||
RECORDER_ARG(f), \
|
|
||||||
RECORDER_ARG(g), \
|
|
||||||
RECORDER_ARG(h))
|
|
||||||
#define RECORD_9(Name, Format, a,b,c,d,e,f,g,h,i) \
|
|
||||||
recorder_append3(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d), \
|
|
||||||
RECORDER_ARG(e), \
|
|
||||||
RECORDER_ARG(f), \
|
|
||||||
RECORDER_ARG(g), \
|
|
||||||
RECORDER_ARG(h), \
|
|
||||||
RECORDER_ARG(i), 0,0,0)
|
|
||||||
#define RECORD_10(Name, Format, a,b,c,d,e,f,g,h,i,j) \
|
|
||||||
recorder_append3(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d), \
|
|
||||||
RECORDER_ARG(e), \
|
|
||||||
RECORDER_ARG(f), \
|
|
||||||
RECORDER_ARG(g), \
|
|
||||||
RECORDER_ARG(h), \
|
|
||||||
RECORDER_ARG(i), \
|
|
||||||
RECORDER_ARG(j), 0,0)
|
|
||||||
#define RECORD_11(Name, Format, a,b,c,d,e,f,g,h,i,j,k) \
|
|
||||||
recorder_append3(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d), \
|
|
||||||
RECORDER_ARG(e), \
|
|
||||||
RECORDER_ARG(f), \
|
|
||||||
RECORDER_ARG(g), \
|
|
||||||
RECORDER_ARG(h), \
|
|
||||||
RECORDER_ARG(i), \
|
|
||||||
RECORDER_ARG(j), \
|
|
||||||
RECORDER_ARG(k),0)
|
|
||||||
#define RECORD_12(Name,Format,a,b,c,d,e,f,g,h,i,j,k,l) \
|
|
||||||
recorder_append3(RECORDER_INFO(Name), \
|
|
||||||
RECORDER_SOURCE_FUNCTION, \
|
|
||||||
RECORDER_SOURCE_LOCATION \
|
|
||||||
Format, \
|
|
||||||
RECORDER_ARG(a), \
|
|
||||||
RECORDER_ARG(b), \
|
|
||||||
RECORDER_ARG(c), \
|
|
||||||
RECORDER_ARG(d), \
|
|
||||||
RECORDER_ARG(e), \
|
|
||||||
RECORDER_ARG(f), \
|
|
||||||
RECORDER_ARG(g), \
|
|
||||||
RECORDER_ARG(h), \
|
|
||||||
RECORDER_ARG(i), \
|
|
||||||
RECORDER_ARG(j), \
|
|
||||||
RECORDER_ARG(k), \
|
|
||||||
RECORDER_ARG(l))
|
|
||||||
#define RECORD_X(Name, ...) RECORD_TOO_MANY_ARGS(printf(__VA_ARGS__))
|
|
||||||
|
|
||||||
|
|
||||||
// Some ugly macro drudgery to make things easy to use. Adjust type.
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define RECORDER_ARG(arg) _recorder_arg(arg)
|
|
||||||
#else // !__cplusplus
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
|
||||||
# if __GNUC__ <= 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
|
|
||||||
# define RECORDER_WITHOUT_GENERIC
|
|
||||||
# endif
|
|
||||||
#endif // __GNUC__
|
|
||||||
|
|
||||||
#ifdef RECORDER_WITHOUT_GENERIC
|
|
||||||
#define RECORDER_ARG(arg) ((uintptr_t) (arg))
|
|
||||||
#else // !RECORDER_WITHOUT_GENERIC
|
|
||||||
#define RECORDER_ARG(arg) \
|
|
||||||
_Generic(arg, \
|
|
||||||
unsigned char: _recorder_unsigned, \
|
|
||||||
unsigned short: _recorder_unsigned, \
|
|
||||||
unsigned: _recorder_unsigned, \
|
|
||||||
unsigned long: _recorder_unsigned, \
|
|
||||||
unsigned long long:_recorder_unsigned, \
|
|
||||||
char: _recorder_char, \
|
|
||||||
signed char: _recorder_signed, \
|
|
||||||
signed short: _recorder_signed, \
|
|
||||||
signed: _recorder_signed, \
|
|
||||||
signed long: _recorder_signed, \
|
|
||||||
signed long long: _recorder_signed, \
|
|
||||||
float: _recorder_float, \
|
|
||||||
double: _recorder_double, \
|
|
||||||
default: _recorder_pointer)(arg)
|
|
||||||
#endif // RECORDER_WITHOUT_GENERIC
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Timing information
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#define RECORD_TIMING_BEGIN(rec) \
|
|
||||||
do { RECORD(rec, "begin");
|
|
||||||
#define RECORD_TIMING_END(rec, op, name, value) \
|
|
||||||
RECORD(rec, "end" op name); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Support macros
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#define RECORDER_SOURCE_FUNCTION __func__ /* Works in C99 and C++11 */
|
|
||||||
#define RECORDER_SOURCE_LOCATION __FILE__ ":" RECORDER_STRING(__LINE__) ":"
|
|
||||||
#define RECORDER_STRING(LINE) RECORDER_STRING_(LINE)
|
|
||||||
#define RECORDER_STRING_(LINE) #LINE
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define RECORDER_CONSTRUCTOR __attribute__((constructor))
|
|
||||||
#else
|
|
||||||
#define RECORDER_CONSTRUCTOR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// Utility: Convert floating point values for vararg format
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
//
|
|
||||||
// The recorder stores only uintptr_t in recorder entries. Integer types
|
|
||||||
// are promoted, pointer types are converted. Floating point values
|
|
||||||
// are converted a floating point type of the same size as uintptr_t,
|
|
||||||
// i.e. float are converted to double on 64-bit platforms, and conversely.
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// In C++, we don't use _Generic but actual overloading
|
|
||||||
template <class inttype>
|
|
||||||
static inline uintptr_t _recorder_arg(inttype i)
|
|
||||||
{
|
|
||||||
return (uintptr_t) i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline uintptr_t _recorder_arg(const std::string &arg)
|
|
||||||
{
|
|
||||||
return (uintptr_t) arg.c_str();
|
|
||||||
}
|
|
||||||
#define _recorder_float _recorder_arg
|
|
||||||
#define _recorder_double _recorder_arg
|
|
||||||
|
|
||||||
#else // !__cplusplus
|
|
||||||
|
|
||||||
static inline uintptr_t _recorder_char(char c)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Necessary because of the way generic selections work
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline uintptr_t _recorder_unsigned(uintptr_t i)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Necessary because of the way generic selections work
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline uintptr_t _recorder_signed(intptr_t i)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Necessary because of the way generic selections work
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
return (uintptr_t) i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline uintptr_t _recorder_pointer(const void *i)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Necessary because of the way generic selections work
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
return (uintptr_t) i;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
|
|
||||||
static inline uintptr_t _recorder_float(float f)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Convert floating point number to intptr_t representation for recorder
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
if (sizeof(float) == sizeof(intptr_t)) {
|
|
||||||
union { float f; uintptr_t i; } u;
|
|
||||||
u.f = f;
|
|
||||||
return u.i;
|
|
||||||
} else {
|
|
||||||
union { double d; uintptr_t i; } u;
|
|
||||||
u.d = (double) f;
|
|
||||||
return u.i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline uintptr_t _recorder_double(double d)
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Convert double-precision floating point number to intptr_t representation
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
{
|
|
||||||
if (sizeof(double) == sizeof(intptr_t)) {
|
|
||||||
union { double d; uintptr_t i; } u;
|
|
||||||
u.d = d;
|
|
||||||
return u.i;
|
|
||||||
} else {
|
|
||||||
// Better to lose precision than not store any data
|
|
||||||
union { float f; uintptr_t i; } u;
|
|
||||||
u.f = d;
|
|
||||||
return u.i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Agent-Interface specific definitions
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
// launch the Agent-Interface server socket
|
|
||||||
extern void agent_interface_start(unsigned int port);
|
|
||||||
|
|
||||||
//
|
|
||||||
typedef void (*forward_quality_cb_t)(void *, const char *);
|
|
||||||
extern void agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data);
|
|
||||||
|
|
||||||
// set a callback function triggered when a new client connects to the socket
|
|
||||||
typedef int (*on_connect_cb_t)(void *);
|
|
||||||
extern void agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
|
||||||
@ -22,20 +22,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <unistd.h>
|
||||||
#if !defined(WIN32) || defined(__MINGW32__)
|
|
||||||
|
|
||||||
#include "backtrace.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "spice_common.h"
|
||||||
|
|
||||||
#define GSTACK_PATH "/usr/bin/gstack"
|
#define GSTACK_PATH "/usr/bin/gstack"
|
||||||
|
|
||||||
#if HAVE_EXECINFO_H
|
#if HAVE_EXECINFO_H
|
||||||
@ -77,6 +75,7 @@ static int spice_backtrace_gstack(void)
|
|||||||
/* CHILD */
|
/* CHILD */
|
||||||
char parent[16];
|
char parent[16];
|
||||||
|
|
||||||
|
seteuid(0);
|
||||||
close(STDIN_FILENO);
|
close(STDIN_FILENO);
|
||||||
close(STDOUT_FILENO);
|
close(STDOUT_FILENO);
|
||||||
dup2(pipefd[1],STDOUT_FILENO);
|
dup2(pipefd[1],STDOUT_FILENO);
|
||||||
@ -132,4 +131,3 @@ void spice_backtrace(void)
|
|||||||
spice_backtrace_backtrace();
|
spice_backtrace_backtrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|||||||
@ -16,8 +16,8 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_BACKTRACE
|
#ifndef BACKTRACE_H
|
||||||
#define H_SPICE_COMMON_BACKTRACE
|
#define BACKTRACE_H
|
||||||
|
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
@ -31,4 +31,4 @@ void spice_backtrace(void);
|
|||||||
|
|
||||||
SPICE_END_DECLS
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_BACKTRACE
|
#endif // BACKTRACE_H
|
||||||
|
|||||||
91
common/bitops.h
Normal file
91
common/bitops.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BITOPS_H
|
||||||
|
#define BITOPS_H
|
||||||
|
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||||
|
static inline int spice_bit_find_msb(unsigned int val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
asm ("bsrl %1,%0\n\t"
|
||||||
|
"jnz 1f\n\t"
|
||||||
|
"movl $-1,%0\n"
|
||||||
|
"1:"
|
||||||
|
: "=r"(ret) : "r"(val));
|
||||||
|
return ret + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(WIN32) && !defined(_WIN64)
|
||||||
|
static INLINE int spice_bit_find_msb(uint32_t val)
|
||||||
|
{
|
||||||
|
uint32_t r;
|
||||||
|
__asm {
|
||||||
|
bsr eax, val
|
||||||
|
jnz found
|
||||||
|
mov eax, -1
|
||||||
|
|
||||||
|
found:
|
||||||
|
mov r, eax
|
||||||
|
}
|
||||||
|
return r + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static INLINE int spice_bit_find_msb(unsigned int val)
|
||||||
|
{
|
||||||
|
signed char index = 31;
|
||||||
|
|
||||||
|
if(val == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(val & 0x80000000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
val <<= 1;
|
||||||
|
} while(--index >= 0);
|
||||||
|
|
||||||
|
return index+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static INLINE int spice_bit_next_pow2(unsigned int val)
|
||||||
|
{
|
||||||
|
if ((val & (val - 1)) == 0) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return 1 << spice_bit_find_msb(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
1122
common/canvas_base.c
1122
common/canvas_base.c
File diff suppressed because it is too large
Load Diff
@ -16,17 +16,24 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_CANVAS_BASE
|
#ifndef _H_CANVAS_BASE
|
||||||
#define H_SPICE_COMMON_CANVAS_BASE
|
#define _H_CANVAS_BASE
|
||||||
|
|
||||||
#include <spice/macros.h>
|
#ifndef SPICE_CANVAS_INTERNAL
|
||||||
|
#error "This header shouldn't be included directly"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
#include "lz.h"
|
#include "lz.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void (*spice_destroy_fn_t)(void *data);
|
typedef void (*spice_destroy_fn_t)(void *data);
|
||||||
|
|
||||||
@ -57,7 +64,7 @@ typedef struct {
|
|||||||
} SpiceImageCacheOps;
|
} SpiceImageCacheOps;
|
||||||
|
|
||||||
struct _SpiceImageCache {
|
struct _SpiceImageCache {
|
||||||
const SpiceImageCacheOps *ops;
|
SpiceImageCacheOps *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -66,7 +73,7 @@ typedef struct {
|
|||||||
} SpiceImageSurfacesOps;
|
} SpiceImageSurfacesOps;
|
||||||
|
|
||||||
struct _SpiceImageSurfaces {
|
struct _SpiceImageSurfaces {
|
||||||
const SpiceImageSurfacesOps *ops;
|
SpiceImageSurfacesOps *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -130,7 +137,6 @@ typedef struct {
|
|||||||
void (*draw_text)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text);
|
void (*draw_text)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text);
|
||||||
void (*draw_stroke)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke);
|
void (*draw_stroke)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke);
|
||||||
void (*draw_rop3)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3);
|
void (*draw_rop3)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3);
|
||||||
void (*draw_composite)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceComposite *composite);
|
|
||||||
void (*draw_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend);
|
void (*draw_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend);
|
||||||
void (*draw_blackness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness);
|
void (*draw_blackness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness);
|
||||||
void (*draw_whiteness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness);
|
void (*draw_whiteness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness);
|
||||||
@ -138,6 +144,9 @@ typedef struct {
|
|||||||
void (*draw_transparent)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent);
|
void (*draw_transparent)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent);
|
||||||
void (*draw_alpha_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend* alpha_blend);
|
void (*draw_alpha_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend* alpha_blend);
|
||||||
void (*put_image)(SpiceCanvas *canvas,
|
void (*put_image)(SpiceCanvas *canvas,
|
||||||
|
#ifdef WIN32
|
||||||
|
HDC dc,
|
||||||
|
#endif
|
||||||
const SpiceRect *dest, const uint8_t *src_data,
|
const SpiceRect *dest, const uint8_t *src_data,
|
||||||
uint32_t src_width, uint32_t src_height, int src_stride,
|
uint32_t src_width, uint32_t src_height, int src_stride,
|
||||||
const QRegion *clip);
|
const QRegion *clip);
|
||||||
@ -301,13 +310,18 @@ typedef struct {
|
|||||||
void (*copy_region)(SpiceCanvas *canvas,
|
void (*copy_region)(SpiceCanvas *canvas,
|
||||||
pixman_region32_t *dest_region,
|
pixman_region32_t *dest_region,
|
||||||
int dx, int dy);
|
int dx, int dy);
|
||||||
pixman_image_t *(*get_image)(SpiceCanvas *canvas, int force_opaque);
|
pixman_image_t *(*get_image)(SpiceCanvas *canvas);
|
||||||
} SpiceCanvasOps;
|
} SpiceCanvasOps;
|
||||||
|
|
||||||
|
void spice_canvas_set_usr_data(SpiceCanvas *canvas, void *data, spice_destroy_fn_t destroy_fn);
|
||||||
|
void *spice_canvas_get_usr_data(SpiceCanvas *canvas);
|
||||||
|
|
||||||
struct _SpiceCanvas {
|
struct _SpiceCanvas {
|
||||||
SpiceCanvasOps *ops;
|
SpiceCanvasOps *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -15,21 +15,42 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "canvas_utils.h"
|
#include "canvas_utils.h"
|
||||||
|
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
|
||||||
typedef struct PixmanData {
|
#ifdef WIN32
|
||||||
uint8_t *data;
|
static int gdi_handlers = 0;
|
||||||
pixman_format_code_t format;
|
#endif
|
||||||
} PixmanData;
|
|
||||||
|
|
||||||
static void release_data(SPICE_GNUC_UNUSED pixman_image_t *image,
|
#ifndef CANVAS_ERROR
|
||||||
void *release_data)
|
#define CANVAS_ERROR(format, ...) { \
|
||||||
|
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__); \
|
||||||
|
abort(); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void release_data(pixman_image_t *image, void *release_data)
|
||||||
{
|
{
|
||||||
PixmanData *data = (PixmanData *)release_data;
|
PixmanData *data = (PixmanData *)release_data;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (data->bitmap) {
|
||||||
|
DeleteObject((HBITMAP)data->bitmap);
|
||||||
|
CloseHandle(data->mutex);
|
||||||
|
gdi_handlers--;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
free(data->data);
|
free(data->data);
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
@ -44,7 +65,7 @@ pixman_image_add_data(pixman_image_t *image)
|
|||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
data = (PixmanData *)calloc(1, sizeof(PixmanData));
|
data = (PixmanData *)calloc(1, sizeof(PixmanData));
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
spice_error("out of memory");
|
CANVAS_ERROR("out of memory");
|
||||||
}
|
}
|
||||||
pixman_image_set_destroy_function(image,
|
pixman_image_set_destroy_function(image,
|
||||||
release_data,
|
release_data,
|
||||||
@ -64,25 +85,21 @@ spice_pixman_image_set_format(pixman_image_t *image,
|
|||||||
data->format = format;
|
data->format = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pixman_format_code_t
|
||||||
int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format)
|
spice_pixman_image_get_format(pixman_image_t *image)
|
||||||
{
|
{
|
||||||
PixmanData *data;
|
PixmanData *data;
|
||||||
|
|
||||||
spice_return_val_if_fail(format != NULL, 0);
|
|
||||||
|
|
||||||
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
||||||
if (data != NULL && data->format != 0) {
|
if (data != NULL &&
|
||||||
*format = data->format;
|
data->format != 0)
|
||||||
return 1;
|
return data->format;
|
||||||
}
|
|
||||||
|
|
||||||
spice_warn_if_reached();
|
CANVAS_ERROR("Unknown pixman image type");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t format, int width, int height,
|
||||||
int stride)
|
int stride)
|
||||||
{
|
{
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
uint8_t *stride_data;
|
uint8_t *stride_data;
|
||||||
@ -100,8 +117,7 @@ pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, in
|
|||||||
|
|
||||||
if (surface == NULL) {
|
if (surface == NULL) {
|
||||||
free(data);
|
free(data);
|
||||||
data = NULL;
|
CANVAS_ERROR("create surface failed, out of memory");
|
||||||
spice_error("create surface failed, out of memory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_data = pixman_image_add_data(surface);
|
pixman_data = pixman_image_add_data(surface);
|
||||||
@ -111,8 +127,98 @@ pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, in
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
|
||||||
|
int width, int height, int top_down)
|
||||||
|
#else
|
||||||
pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
|
pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
/*
|
||||||
|
* Windows xp allow only 10,000 of gdi handlers, considering the fact that
|
||||||
|
* we limit here the number to 5000, we dont use atomic operations to sync
|
||||||
|
* this calculation against the other canvases (in case of multiple
|
||||||
|
* monitors), in worst case there will be little more than 5000 gdi
|
||||||
|
* handlers.
|
||||||
|
*/
|
||||||
|
if (dc && gdi_handlers < 5000) {
|
||||||
|
uint8_t *data;
|
||||||
|
uint8_t *src;
|
||||||
|
struct {
|
||||||
|
BITMAPINFO inf;
|
||||||
|
RGBQUAD palette[255];
|
||||||
|
} bitmap_info;
|
||||||
|
int nstride;
|
||||||
|
pixman_image_t *surface;
|
||||||
|
PixmanData *pixman_data;
|
||||||
|
HBITMAP bitmap;
|
||||||
|
HANDLE mutex;
|
||||||
|
|
||||||
|
memset(&bitmap_info, 0, sizeof(bitmap_info));
|
||||||
|
bitmap_info.inf.bmiHeader.biSize = sizeof(bitmap_info.inf.bmiHeader);
|
||||||
|
bitmap_info.inf.bmiHeader.biWidth = width;
|
||||||
|
|
||||||
|
bitmap_info.inf.bmiHeader.biHeight = (!top_down) ? height : -height;
|
||||||
|
|
||||||
|
bitmap_info.inf.bmiHeader.biPlanes = 1;
|
||||||
|
switch (format) {
|
||||||
|
case PIXMAN_a8r8g8b8:
|
||||||
|
case PIXMAN_x8r8g8b8:
|
||||||
|
bitmap_info.inf.bmiHeader.biBitCount = 32;
|
||||||
|
nstride = width * 4;
|
||||||
|
break;
|
||||||
|
case PIXMAN_x1r5g5b5:
|
||||||
|
case PIXMAN_r5g6b5:
|
||||||
|
bitmap_info.inf.bmiHeader.biBitCount = 16;
|
||||||
|
nstride = SPICE_ALIGN(width * 2, 4);
|
||||||
|
break;
|
||||||
|
case PIXMAN_a8:
|
||||||
|
bitmap_info.inf.bmiHeader.biBitCount = 8;
|
||||||
|
nstride = SPICE_ALIGN(width, 4);
|
||||||
|
break;
|
||||||
|
case PIXMAN_a1:
|
||||||
|
bitmap_info.inf.bmiHeader.biBitCount = 1;
|
||||||
|
nstride = SPICE_ALIGN(width, 32) / 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CANVAS_ERROR("invalid format");
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
|
||||||
|
|
||||||
|
mutex = CreateMutex(NULL, 0, NULL);
|
||||||
|
if (!mutex) {
|
||||||
|
CANVAS_ERROR("Unable to CreateMutex");
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap = CreateDIBSection(dc, &bitmap_info.inf, 0, (VOID **)&data, NULL, 0);
|
||||||
|
if (!bitmap) {
|
||||||
|
CloseHandle(mutex);
|
||||||
|
CANVAS_ERROR("Unable to CreateDIBSection");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top_down) {
|
||||||
|
src = data;
|
||||||
|
} else {
|
||||||
|
src = data + nstride * (height - 1);
|
||||||
|
nstride = -nstride;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface = pixman_image_create_bits(format, width, height, (uint32_t *)src, nstride);
|
||||||
|
if (surface == NULL) {
|
||||||
|
CloseHandle(mutex);
|
||||||
|
DeleteObject(bitmap);
|
||||||
|
CANVAS_ERROR("create surface failed, out of memory");
|
||||||
|
}
|
||||||
|
pixman_data = pixman_image_add_data(surface);
|
||||||
|
pixman_data->format = format;
|
||||||
|
pixman_data->bitmap = bitmap;
|
||||||
|
pixman_data->mutex = mutex;
|
||||||
|
gdi_handlers++;
|
||||||
|
return surface;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
if (top_down) {
|
if (top_down) {
|
||||||
pixman_image_t *surface;
|
pixman_image_t *surface;
|
||||||
PixmanData *data;
|
PixmanData *data;
|
||||||
@ -127,19 +233,8 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
|
|||||||
switch (format) {
|
switch (format) {
|
||||||
case PIXMAN_a8r8g8b8:
|
case PIXMAN_a8r8g8b8:
|
||||||
case PIXMAN_x8r8g8b8:
|
case PIXMAN_x8r8g8b8:
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
case PIXMAN_b8g8r8a8:
|
|
||||||
case PIXMAN_b8g8r8x8:
|
|
||||||
#endif
|
|
||||||
stride = width * 4;
|
stride = width * 4;
|
||||||
break;
|
break;
|
||||||
case PIXMAN_r8g8b8:
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
case PIXMAN_b8g8r8:
|
|
||||||
#endif
|
|
||||||
// NOTE: LZ4 also decodes to RGB24
|
|
||||||
stride = SPICE_ALIGN(width * 3, 4);
|
|
||||||
break;
|
|
||||||
case PIXMAN_x1r5g5b5:
|
case PIXMAN_x1r5g5b5:
|
||||||
case PIXMAN_r5g6b5:
|
case PIXMAN_r5g6b5:
|
||||||
stride = SPICE_ALIGN(width * 2, 4);
|
stride = SPICE_ALIGN(width * 2, 4);
|
||||||
@ -151,11 +246,34 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
|
|||||||
stride = SPICE_ALIGN(width, 32) / 8;
|
stride = SPICE_ALIGN(width, 32) / 8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
spice_error("invalid format");
|
CANVAS_ERROR("invalid format");
|
||||||
}
|
}
|
||||||
stride = -stride;
|
stride = -stride;
|
||||||
return surface_create_stride(format, width, height, stride);
|
return __surface_create_stride(format, width, height, stride);
|
||||||
}
|
}
|
||||||
|
#ifdef WIN32
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
|
||||||
|
int stride)
|
||||||
|
#else
|
||||||
|
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
||||||
|
int stride)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
if (dc) {
|
||||||
|
if (abs(stride) == (width * 4)) {
|
||||||
|
return surface_create(dc, format, width, height, (stride > 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return __surface_create_stride(format, width, height, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
||||||
@ -167,14 +285,15 @@ pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
|||||||
|
|
||||||
stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);
|
stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);
|
||||||
|
|
||||||
/* pixman requires strides to be 4-byte aligned */
|
|
||||||
stride = SPICE_ALIGN(stride, 4);
|
|
||||||
|
|
||||||
if (!top_down) {
|
if (!top_down) {
|
||||||
stride = -stride;
|
stride = -stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
surface = surface_create_stride(pixman_format, width, height, stride);
|
surface = surface_create_stride(
|
||||||
|
#ifdef WIN32
|
||||||
|
canvas_data->dc,
|
||||||
|
#endif
|
||||||
|
pixman_format, width, height, stride);
|
||||||
canvas_data->out_surface = surface;
|
canvas_data->out_surface = surface;
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,29 +16,56 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_CANVAS_UTILS
|
#ifndef _H_CANVAS_UTILS
|
||||||
#define H_SPICE_COMMON_CANVAS_UTILS
|
#define _H_CANVAS_UTILS
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
#include "lz.h"
|
#include "lz.h"
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct PixmanData {
|
||||||
|
#ifdef WIN32
|
||||||
|
HBITMAP bitmap;
|
||||||
|
HANDLE mutex;
|
||||||
|
#endif
|
||||||
|
uint8_t *data;
|
||||||
|
pixman_format_code_t format;
|
||||||
|
} PixmanData;
|
||||||
|
|
||||||
void spice_pixman_image_set_format(pixman_image_t *image,
|
void spice_pixman_image_set_format(pixman_image_t *image,
|
||||||
pixman_format_code_t format);
|
pixman_format_code_t format);
|
||||||
int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format);
|
pixman_format_code_t spice_pixman_image_get_format(pixman_image_t *image);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
|
||||||
|
int width, int height, int top_down);
|
||||||
|
#else
|
||||||
pixman_image_t *surface_create(pixman_format_code_t format, int width, int height, int top_down);
|
pixman_image_t *surface_create(pixman_format_code_t format, int width, int height, int top_down);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
|
||||||
|
int stride);
|
||||||
|
#else
|
||||||
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
||||||
int stride);
|
int stride);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct LzDecodeUsrData {
|
typedef struct LzDecodeUsrData {
|
||||||
|
#ifdef WIN32
|
||||||
|
HDC dc;
|
||||||
|
#endif
|
||||||
pixman_image_t *out_surface;
|
pixman_image_t *out_surface;
|
||||||
} LzDecodeUsrData;
|
} LzDecodeUsrData;
|
||||||
|
|
||||||
@ -46,7 +73,8 @@ typedef struct LzDecodeUsrData {
|
|||||||
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
||||||
pixman_format_code_t pixman_format, int width,
|
pixman_format_code_t pixman_format, int width,
|
||||||
int height, int gross_pixels, int top_down);
|
int height, int gross_pixels, int top_down);
|
||||||
|
#ifdef __cplusplus
|
||||||
SPICE_END_DECLS
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2010 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#ifndef H_SPICE_COMMON_DEMARSHALLERS
|
|
||||||
#define H_SPICE_COMMON_DEMARSHALLERS
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
|
||||||
|
|
||||||
typedef void (*message_destructor_t)(uint8_t *message);
|
|
||||||
typedef uint8_t * (*spice_parse_channel_func_t)(uint8_t *message_start, uint8_t *message_end,
|
|
||||||
uint16_t message_type, int minor,
|
|
||||||
size_t *size_out,
|
|
||||||
message_destructor_t *free_message);
|
|
||||||
|
|
||||||
spice_parse_channel_func_t
|
|
||||||
spice_get_server_channel_parser(uint32_t channel, unsigned int *max_message_type);
|
|
||||||
spice_parse_channel_func_t
|
|
||||||
spice_get_client_channel_parser(uint32_t channel, unsigned int *max_message_type);
|
|
||||||
|
|
||||||
SPICE_END_DECLS
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -28,15 +28,16 @@
|
|||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_DRAW
|
#ifndef _H_SPICE_DRAW
|
||||||
#define H_SPICE_COMMON_DRAW
|
#define _H_SPICE_DRAW
|
||||||
|
|
||||||
#include <spice/macros.h>
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/enums.h>
|
#include <spice/enums.h>
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SPICE_GET_ADDRESS(addr) ((void *)(uintptr_t)(addr))
|
#define SPICE_GET_ADDRESS(addr) ((void *)(uintptr_t)(addr))
|
||||||
#define SPICE_SET_ADDRESS(addr, val) ((addr) = (uintptr_t)(val))
|
#define SPICE_SET_ADDRESS(addr, val) ((addr) = (uintptr_t)(val))
|
||||||
@ -82,7 +83,7 @@ typedef struct SpiceClipRects {
|
|||||||
} SpiceClipRects;
|
} SpiceClipRects;
|
||||||
|
|
||||||
typedef struct SpiceClip {
|
typedef struct SpiceClip {
|
||||||
uint8_t type;
|
uint32_t type;
|
||||||
SpiceClipRects *rects;
|
SpiceClipRects *rects;
|
||||||
} SpiceClip;
|
} SpiceClip;
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ typedef struct SpiceSurface {
|
|||||||
typedef struct SpiceQUICData {
|
typedef struct SpiceQUICData {
|
||||||
uint32_t data_size;
|
uint32_t data_size;
|
||||||
SpiceChunks *data;
|
SpiceChunks *data;
|
||||||
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData, SpiceLZ4Data;
|
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData;
|
||||||
|
|
||||||
typedef struct SpiceLZPLTData {
|
typedef struct SpiceLZPLTData {
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
@ -153,7 +154,6 @@ typedef struct SpiceImage {
|
|||||||
SpiceLZRGBData lz_rgb;
|
SpiceLZRGBData lz_rgb;
|
||||||
SpiceLZPLTData lz_plt;
|
SpiceLZPLTData lz_plt;
|
||||||
SpiceJPEGData jpeg;
|
SpiceJPEGData jpeg;
|
||||||
SpiceLZ4Data lz4;
|
|
||||||
SpiceZlibGlzRGBData zlib_glz;
|
SpiceZlibGlzRGBData zlib_glz;
|
||||||
SpiceJPEGAlphaData jpeg_alpha;
|
SpiceJPEGAlphaData jpeg_alpha;
|
||||||
} u;
|
} u;
|
||||||
@ -224,26 +224,6 @@ typedef struct SpiceRop3 {
|
|||||||
SpiceQMask mask;
|
SpiceQMask mask;
|
||||||
} SpiceRop3;
|
} SpiceRop3;
|
||||||
|
|
||||||
/* Given in 16.16 fixed point */
|
|
||||||
typedef struct SpiceTransform {
|
|
||||||
uint32_t t00;
|
|
||||||
uint32_t t01;
|
|
||||||
uint32_t t02;
|
|
||||||
uint32_t t10;
|
|
||||||
uint32_t t11;
|
|
||||||
uint32_t t12;
|
|
||||||
} SpiceTransform;
|
|
||||||
|
|
||||||
typedef struct SpiceComposite {
|
|
||||||
uint32_t flags;
|
|
||||||
SpiceImage *src_bitmap;
|
|
||||||
SpiceImage *mask_bitmap;
|
|
||||||
SpiceTransform src_transform;
|
|
||||||
SpiceTransform mask_transform;
|
|
||||||
SpicePoint16 src_origin;
|
|
||||||
SpicePoint16 mask_origin;
|
|
||||||
} SpiceComposite;
|
|
||||||
|
|
||||||
typedef struct SpiceBlackness {
|
typedef struct SpiceBlackness {
|
||||||
SpiceQMask mask;
|
SpiceQMask mask;
|
||||||
} SpiceBlackness, SpiceInvers, SpiceWhiteness;
|
} SpiceBlackness, SpiceInvers, SpiceWhiteness;
|
||||||
@ -294,12 +274,8 @@ typedef struct SpiceCursorHeader {
|
|||||||
uint16_t hot_spot_y;
|
uint16_t hot_spot_y;
|
||||||
} SpiceCursorHeader;
|
} SpiceCursorHeader;
|
||||||
|
|
||||||
static inline int spice_image_descriptor_is_lossy(const SpiceImageDescriptor *descriptor)
|
#ifdef __cplusplus
|
||||||
{
|
|
||||||
return descriptor->type == SPICE_IMAGE_TYPE_JPEG ||
|
|
||||||
descriptor->type == SPICE_IMAGE_TYPE_JPEG_ALPHA;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#endif /* _H_SPICE_DRAW */
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_DRAW
|
|
||||||
|
|||||||
1858
common/gdi_canvas.c
Normal file
1858
common/gdi_canvas.c
Normal file
File diff suppressed because it is too large
Load Diff
51
common/gdi_canvas.h
Normal file
51
common/gdi_canvas.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _H__GDI_CANVAS
|
||||||
|
#define _H__GDI_CANVAS
|
||||||
|
|
||||||
|
#ifndef SPICE_CANVAS_INTERNAL
|
||||||
|
#error "This header shouldn't be included directly"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "pixman_utils.h"
|
||||||
|
#include "canvas_base.h"
|
||||||
|
#include "region.h"
|
||||||
|
|
||||||
|
SpiceCanvas *gdi_canvas_create(int width, int height,
|
||||||
|
HDC dc, class RecurciveMutex *lock, uint32_t format,
|
||||||
|
SpiceImageCache *bits_cache,
|
||||||
|
SpicePaletteCache *palette_cache,
|
||||||
|
SpiceImageSurfaces *surfaces,
|
||||||
|
SpiceGlzDecoder *glz_decoder,
|
||||||
|
SpiceJpegDecoder *jpeg_decoder,
|
||||||
|
SpiceZlibDecoder *zlib_decoder);
|
||||||
|
|
||||||
|
void gdi_canvas_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
906
common/gl_canvas.c
Normal file
906
common/gl_canvas.c
Normal file
@ -0,0 +1,906 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SPICE_CANVAS_INTERNAL
|
||||||
|
#error "This file shouldn't be compiled directly"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "quic.h"
|
||||||
|
#include "rop3.h"
|
||||||
|
#include "region.h"
|
||||||
|
|
||||||
|
#define GL_CANVAS
|
||||||
|
#include "canvas_base.c"
|
||||||
|
|
||||||
|
typedef struct GLCanvas GLCanvas;
|
||||||
|
|
||||||
|
struct GLCanvas {
|
||||||
|
CanvasBase base;
|
||||||
|
GLCCtx glc;
|
||||||
|
void *private_data;
|
||||||
|
int private_data_size;
|
||||||
|
int textures_lost;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint8_t *copy_opposite_image(GLCanvas *canvas, void *data, int stride, int height)
|
||||||
|
{
|
||||||
|
uint8_t *ret_data = (uint8_t *)data;
|
||||||
|
uint8_t *dest;
|
||||||
|
uint8_t *src;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!canvas->private_data) {
|
||||||
|
canvas->private_data = spice_malloc_n(height, stride);
|
||||||
|
if (!canvas->private_data) {
|
||||||
|
return ret_data;
|
||||||
|
}
|
||||||
|
canvas->private_data_size = stride * height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canvas->private_data_size < (stride * height)) {
|
||||||
|
free(canvas->private_data);
|
||||||
|
canvas->private_data = spice_malloc_n(height, stride);
|
||||||
|
if (!canvas->private_data) {
|
||||||
|
return ret_data;
|
||||||
|
}
|
||||||
|
canvas->private_data_size = stride * height;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest = (uint8_t *)canvas->private_data;
|
||||||
|
src = (uint8_t *)data + (height - 1) * stride;
|
||||||
|
|
||||||
|
for (i = 0; i < height; ++i) {
|
||||||
|
memcpy(dest, src, stride);
|
||||||
|
dest += stride;
|
||||||
|
src -= stride;
|
||||||
|
}
|
||||||
|
return (uint8_t *)canvas->private_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pixman_image_t *canvas_surf_to_trans_surf(GLCImage *image,
|
||||||
|
uint32_t trans_color)
|
||||||
|
{
|
||||||
|
int width = image->width;
|
||||||
|
int height = image->height;
|
||||||
|
uint8_t *src_line;
|
||||||
|
uint8_t *end_src_line;
|
||||||
|
int src_stride;
|
||||||
|
uint8_t *dest_line;
|
||||||
|
int dest_stride;
|
||||||
|
pixman_image_t *ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ret = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, 0);
|
||||||
|
if (ret == NULL) {
|
||||||
|
CANVAS_ERROR("create surface failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
src_line = image->pixels;
|
||||||
|
src_stride = image->stride;
|
||||||
|
end_src_line = src_line + src_stride * height;
|
||||||
|
|
||||||
|
dest_line = (uint8_t *)pixman_image_get_data(ret);
|
||||||
|
dest_stride = pixman_image_get_stride(ret);
|
||||||
|
|
||||||
|
for (; src_line < end_src_line; src_line += src_stride, dest_line += dest_stride) {
|
||||||
|
for (i = 0; i < width; i++) {
|
||||||
|
if ((((uint32_t*)src_line)[i] & 0x00ffffff) == trans_color) {
|
||||||
|
((uint32_t*)dest_line)[i] = 0;
|
||||||
|
} else {
|
||||||
|
((uint32_t*)dest_line)[i] = (((uint32_t*)src_line)[i]) | 0xff000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLCPath get_path(GLCanvas *canvas, SpicePath *s)
|
||||||
|
{
|
||||||
|
GLCPath path = glc_path_create(canvas->glc);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < s->num_segments; i++) {
|
||||||
|
SpicePathSeg* seg = s->segments[i];
|
||||||
|
SpicePointFix* point = seg->points;
|
||||||
|
SpicePointFix* end_point = point + seg->count;
|
||||||
|
|
||||||
|
if (seg->flags & SPICE_PATH_BEGIN) {
|
||||||
|
glc_path_move_to(path, fix_to_double(point->x), fix_to_double(point->y));
|
||||||
|
point++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seg->flags & SPICE_PATH_BEZIER) {
|
||||||
|
ASSERT((point - end_point) % 3 == 0);
|
||||||
|
for (; point + 2 < end_point; point += 3) {
|
||||||
|
glc_path_curve_to(path,
|
||||||
|
fix_to_double(point[0].x), fix_to_double(point[0].y),
|
||||||
|
fix_to_double(point[1].x), fix_to_double(point[1].y),
|
||||||
|
fix_to_double(point[2].x), fix_to_double(point[2].y));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (; point < end_point; point++) {
|
||||||
|
glc_path_line_to(path, fix_to_double(point->x), fix_to_double(point->y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (seg->flags & SPICE_PATH_END) {
|
||||||
|
if (seg->flags & SPICE_PATH_CLOSE) {
|
||||||
|
glc_path_close(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SET_GLC_RECT(dest, src) { \
|
||||||
|
(dest)->x = (src)->left; \
|
||||||
|
(dest)->y = (src)->top; \
|
||||||
|
(dest)->width = (src)->right - (src)->left; \
|
||||||
|
(dest)->height = (src)->bottom - (src)->top; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SET_GLC_BOX(dest, src) { \
|
||||||
|
(dest)->x = (src)->x1; \
|
||||||
|
(dest)->y = (src)->y1; \
|
||||||
|
(dest)->width = (src)->x2 - (src)->x1; \
|
||||||
|
(dest)->height = (src)->y2 - (src)->y1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_clip(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip)
|
||||||
|
{
|
||||||
|
GLCRect rect;
|
||||||
|
glc_clip_reset(canvas->glc);
|
||||||
|
|
||||||
|
switch (clip->type) {
|
||||||
|
case SPICE_CLIP_TYPE_NONE:
|
||||||
|
break;
|
||||||
|
case SPICE_CLIP_TYPE_RECTS: {
|
||||||
|
uint32_t n = clip->rects->num_rects;
|
||||||
|
SpiceRect *now = clip->rects->rects;
|
||||||
|
SpiceRect *end = now + n;
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
rect.x = rect.y = 0;
|
||||||
|
rect.width = rect.height = 0;
|
||||||
|
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
SET_GLC_RECT(&rect, now);
|
||||||
|
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (now++; now < end; now++) {
|
||||||
|
SET_GLC_RECT(&rect, now);
|
||||||
|
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
CANVAS_ERROR("invalid clip type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_mask(GLCanvas *canvas, SpiceQMask *mask, int x, int y)
|
||||||
|
{
|
||||||
|
pixman_image_t *image;
|
||||||
|
|
||||||
|
if (!(image = canvas_get_mask(&canvas->base, mask, NULL))) {
|
||||||
|
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
glc_set_mask(canvas->glc, x - mask->pos.x, y - mask->pos.y,
|
||||||
|
pixman_image_get_width(image),
|
||||||
|
pixman_image_get_height(image),
|
||||||
|
pixman_image_get_stride(image),
|
||||||
|
(uint8_t *)pixman_image_get_data(image), GLC_MASK_A);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void surface_to_image(GLCanvas *canvas, pixman_image_t *surface, GLCImage *image,
|
||||||
|
int ignore_stride)
|
||||||
|
{
|
||||||
|
int depth = pixman_image_get_depth(surface);
|
||||||
|
|
||||||
|
ASSERT(depth == 32 || depth == 24);
|
||||||
|
image->format = (depth == 24) ? GLC_IMAGE_RGB32 : GLC_IMAGE_ARGB32;
|
||||||
|
image->width = pixman_image_get_width(surface);
|
||||||
|
image->height = pixman_image_get_height(surface);
|
||||||
|
image->stride = pixman_image_get_stride(surface);
|
||||||
|
image->pixels = (uint8_t *)pixman_image_get_data(surface);
|
||||||
|
image->pallet = NULL;
|
||||||
|
if (ignore_stride) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (image->stride < 0) {
|
||||||
|
image->stride = -image->stride;
|
||||||
|
image->pixels = image->pixels - (image->height - 1) * image->stride;
|
||||||
|
} else {
|
||||||
|
image->pixels = copy_opposite_image(canvas, image->pixels, image->stride, image->height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_brush(GLCanvas *canvas, SpiceBrush *brush)
|
||||||
|
{
|
||||||
|
switch (brush->type) {
|
||||||
|
case SPICE_BRUSH_TYPE_SOLID: {
|
||||||
|
uint32_t color = brush->u.color;
|
||||||
|
double r, g, b;
|
||||||
|
|
||||||
|
b = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
|
||||||
|
color >>= canvas->base.color_shift;
|
||||||
|
g = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
|
||||||
|
color >>= canvas->base.color_shift;
|
||||||
|
r = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
|
||||||
|
glc_set_rgb(canvas->glc, r, g, b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SPICE_BRUSH_TYPE_PATTERN: {
|
||||||
|
GLCImage image;
|
||||||
|
GLCPattern pattern;
|
||||||
|
pixman_image_t *surface;
|
||||||
|
|
||||||
|
surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
|
||||||
|
surface_to_image(canvas, surface, &image, 0);
|
||||||
|
|
||||||
|
pattern = glc_pattern_create(canvas->glc, -brush->u.pattern.pos.x,
|
||||||
|
-brush->u.pattern.pos.y, &image);
|
||||||
|
|
||||||
|
glc_set_pattern(canvas->glc, pattern);
|
||||||
|
glc_pattern_destroy(pattern);
|
||||||
|
pixman_image_unref (surface);
|
||||||
|
}
|
||||||
|
case SPICE_BRUSH_TYPE_NONE:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
CANVAS_ERROR("invalid brush type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_op(GLCanvas *canvas, uint16_t rop_decriptor)
|
||||||
|
{
|
||||||
|
GLCOp op;
|
||||||
|
|
||||||
|
switch (rop_decriptor) {
|
||||||
|
case SPICE_ROPD_OP_PUT:
|
||||||
|
op = GLC_OP_COPY;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_XOR:
|
||||||
|
op = GLC_OP_XOR;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_BLACKNESS:
|
||||||
|
op = GLC_OP_CLEAR;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_WHITENESS:
|
||||||
|
op = GLC_OP_SET;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_PUT | SPICE_ROPD_INVERS_BRUSH:
|
||||||
|
case SPICE_ROPD_OP_PUT | SPICE_ROPD_INVERS_SRC:
|
||||||
|
op = GLC_OP_COPY_INVERTED;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_INVERS:
|
||||||
|
op = GLC_OP_INVERT;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_AND:
|
||||||
|
op = GLC_OP_AND;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_RES:
|
||||||
|
op = GLC_OP_NAND;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_OR:
|
||||||
|
op = GLC_OP_OR;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_RES:
|
||||||
|
op = GLC_OP_NOR;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_XOR | SPICE_ROPD_INVERS_RES:
|
||||||
|
op = GLC_OP_EQUIV;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_DEST:
|
||||||
|
op = GLC_OP_AND_REVERSE;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_BRUSH:
|
||||||
|
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_SRC:
|
||||||
|
op = GLC_OP_AND_INVERTED;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_DEST:
|
||||||
|
op = GLC_OP_OR_REVERSE;
|
||||||
|
break;
|
||||||
|
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_BRUSH:
|
||||||
|
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_SRC:
|
||||||
|
op = GLC_OP_OR_INVERTED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN("GLC_OP_NOOP");
|
||||||
|
op = GLC_OP_NOOP;
|
||||||
|
}
|
||||||
|
glc_set_op(canvas->glc, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
GLCRect rect;
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
set_mask(canvas, &fill->mask, bbox->left, bbox->top);
|
||||||
|
set_brush(canvas, &fill->brush);
|
||||||
|
set_op(canvas, fill->rop_descriptor);
|
||||||
|
SET_GLC_RECT(&rect, bbox);
|
||||||
|
|
||||||
|
glc_fill_rect(canvas->glc, &rect);
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
pixman_image_t *surface;
|
||||||
|
GLCRecti src;
|
||||||
|
GLCRecti dest;
|
||||||
|
GLCImage image;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
set_mask(canvas, ©->mask, bbox->left, bbox->top);
|
||||||
|
set_op(canvas, copy->rop_descriptor);
|
||||||
|
|
||||||
|
//todo: optimize get_image (use ogl conversion + remove unnecessary copy of 32bpp)
|
||||||
|
surface = canvas_get_image(&canvas->base, copy->src_bitmap, FALSE);
|
||||||
|
surface_to_image(canvas, surface, &image, 0);
|
||||||
|
SET_GLC_RECT(&dest, bbox);
|
||||||
|
SET_GLC_RECT(&src, ©->src_area);
|
||||||
|
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
||||||
|
|
||||||
|
pixman_image_unref(surface);
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
pixman_image_t *surface;
|
||||||
|
GLCRecti src;
|
||||||
|
GLCRecti dest;
|
||||||
|
GLCRect fill_rect;
|
||||||
|
GLCImage image;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
set_mask(canvas, &opaque->mask, bbox->left, bbox->top);
|
||||||
|
|
||||||
|
glc_set_op(canvas->glc, (opaque->rop_descriptor & SPICE_ROPD_INVERS_SRC) ? GLC_OP_COPY_INVERTED :
|
||||||
|
GLC_OP_COPY);
|
||||||
|
surface = canvas_get_image(&canvas->base, opaque->src_bitmap, FALSE);
|
||||||
|
surface_to_image(canvas, surface, &image, 0);
|
||||||
|
SET_GLC_RECT(&dest, bbox);
|
||||||
|
SET_GLC_RECT(&src, &opaque->src_area);
|
||||||
|
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
||||||
|
pixman_image_unref(surface);
|
||||||
|
|
||||||
|
set_brush(canvas, &opaque->brush);
|
||||||
|
set_op(canvas, opaque->rop_descriptor & ~SPICE_ROPD_INVERS_SRC);
|
||||||
|
SET_GLC_RECT(&fill_rect, bbox);
|
||||||
|
glc_fill_rect(canvas->glc, &fill_rect);
|
||||||
|
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend *alpha_blend)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
pixman_image_t *surface;
|
||||||
|
GLCRecti src;
|
||||||
|
GLCRecti dest;
|
||||||
|
GLCImage image;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
||||||
|
glc_set_op(canvas->glc, GLC_OP_COPY);
|
||||||
|
|
||||||
|
surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap, FALSE);
|
||||||
|
surface_to_image(canvas, surface, &image, 0);
|
||||||
|
SET_GLC_RECT(&dest, bbox);
|
||||||
|
SET_GLC_RECT(&src, &alpha_blend->src_area);
|
||||||
|
glc_draw_image(canvas->glc, &dest, &src, &image, 0, (double)alpha_blend->alpha / 0xff);
|
||||||
|
|
||||||
|
pixman_image_unref(surface);
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
pixman_image_t *surface;
|
||||||
|
GLCRecti src;
|
||||||
|
GLCRecti dest;
|
||||||
|
GLCImage image;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
set_mask(canvas, &blend->mask, bbox->left, bbox->top);
|
||||||
|
set_op(canvas, blend->rop_descriptor);
|
||||||
|
|
||||||
|
surface = canvas_get_image(&canvas->base, blend->src_bitmap, FALSE);
|
||||||
|
SET_GLC_RECT(&dest, bbox);
|
||||||
|
SET_GLC_RECT(&src, &blend->src_area);
|
||||||
|
surface_to_image(canvas, surface, &image, 0);
|
||||||
|
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
||||||
|
|
||||||
|
pixman_image_unref(surface);
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent *transparent)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
pixman_image_t *surface;
|
||||||
|
pixman_image_t *trans_surf;
|
||||||
|
GLCImage image;
|
||||||
|
GLCRecti src;
|
||||||
|
GLCRecti dest;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
||||||
|
glc_set_op(canvas->glc, GLC_OP_COPY);
|
||||||
|
|
||||||
|
surface = canvas_get_image(&canvas->base, transparent->src_bitmap, FALSE);
|
||||||
|
surface_to_image(canvas, surface, &image, 0);
|
||||||
|
|
||||||
|
trans_surf = canvas_surf_to_trans_surf(&image, transparent->true_color);
|
||||||
|
pixman_image_unref(surface);
|
||||||
|
|
||||||
|
surface_to_image(canvas, trans_surf, &image, 1);
|
||||||
|
SET_GLC_RECT(&dest, bbox);
|
||||||
|
SET_GLC_RECT(&src, &transparent->src_area);
|
||||||
|
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
||||||
|
|
||||||
|
pixman_image_unref(trans_surf);
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void fill_common(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceQMask * mask, GLCOp op)
|
||||||
|
{
|
||||||
|
GLCRect rect;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
set_mask(canvas, mask, bbox->left, bbox->top);
|
||||||
|
glc_set_op(canvas->glc, op);
|
||||||
|
SET_GLC_RECT(&rect, bbox);
|
||||||
|
glc_fill_rect(canvas->glc, &rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
fill_common(canvas, bbox, clip, &whiteness->mask, GLC_OP_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
fill_common(canvas, bbox, clip, &blackness->mask, GLC_OP_CLEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
fill_common(canvas, bbox, clip, &invers->mask, GLC_OP_INVERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
pixman_image_t *d;
|
||||||
|
pixman_image_t *s;
|
||||||
|
GLCImage image;
|
||||||
|
SpicePoint src_pos;
|
||||||
|
uint8_t *data_opp;
|
||||||
|
int src_stride;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
set_mask(canvas, &rop3->mask, bbox->left, bbox->top);
|
||||||
|
|
||||||
|
glc_set_op(canvas->glc, GLC_OP_COPY);
|
||||||
|
|
||||||
|
image.format = GLC_IMAGE_RGB32;
|
||||||
|
image.width = bbox->right - bbox->left;
|
||||||
|
image.height = bbox->bottom - bbox->top;
|
||||||
|
|
||||||
|
image.pallet = NULL;
|
||||||
|
|
||||||
|
d = pixman_image_create_bits(PIXMAN_x8r8g8b8, image.width, image.height, NULL, 0);
|
||||||
|
if (d == NULL) {
|
||||||
|
CANVAS_ERROR("create surface failed");
|
||||||
|
}
|
||||||
|
image.pixels = (uint8_t *)pixman_image_get_data(d);
|
||||||
|
image.stride = pixman_image_get_stride(d);
|
||||||
|
|
||||||
|
glc_read_pixels(canvas->glc, bbox->left, bbox->top, &image);
|
||||||
|
data_opp = copy_opposite_image(canvas, image.pixels,
|
||||||
|
image.stride,
|
||||||
|
pixman_image_get_height(d));
|
||||||
|
memcpy(image.pixels, data_opp,
|
||||||
|
image.stride * pixman_image_get_height(d));
|
||||||
|
|
||||||
|
s = canvas_get_image(&canvas->base, rop3->src_bitmap, FALSE);
|
||||||
|
src_stride = pixman_image_get_stride(s);
|
||||||
|
if (src_stride > 0) {
|
||||||
|
data_opp = copy_opposite_image(canvas, (uint8_t *)pixman_image_get_data(s),
|
||||||
|
src_stride, pixman_image_get_height(s));
|
||||||
|
memcpy((uint8_t *)pixman_image_get_data(s), data_opp,
|
||||||
|
src_stride * pixman_image_get_height(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rect_is_same_size(bbox, &rop3->src_area)) {
|
||||||
|
pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, image.width,
|
||||||
|
image.height, rop3->scale_mode);
|
||||||
|
pixman_image_unref(s);
|
||||||
|
s = scaled_s;
|
||||||
|
src_pos.x = 0;
|
||||||
|
src_pos.y = 0;
|
||||||
|
} else {
|
||||||
|
src_pos.x = rop3->src_area.left;
|
||||||
|
src_pos.y = rop3->src_area.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixman_image_get_width(s) - src_pos.x < image.width ||
|
||||||
|
pixman_image_get_height(s) - src_pos.y < image.height) {
|
||||||
|
CANVAS_ERROR("bad src bitmap size");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
|
||||||
|
pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat, FALSE);
|
||||||
|
SpicePoint pat_pos;
|
||||||
|
|
||||||
|
pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
|
||||||
|
|
||||||
|
pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p);
|
||||||
|
|
||||||
|
//for now (bottom-top)
|
||||||
|
if (pat_pos.y < 0) {
|
||||||
|
pat_pos.y = pixman_image_get_height(p) + pat_pos.y;
|
||||||
|
}
|
||||||
|
pat_pos.y = (image.height + pat_pos.y) % pixman_image_get_height(p);
|
||||||
|
pat_pos.y = pixman_image_get_height(p) - pat_pos.y;
|
||||||
|
|
||||||
|
do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
|
||||||
|
pixman_image_unref(p);
|
||||||
|
} else {
|
||||||
|
uint32_t color = (canvas->base.color_shift) == 8 ? rop3->brush.u.color :
|
||||||
|
canvas_16bpp_to_32bpp(rop3->brush.u.color);
|
||||||
|
do_rop3_with_color(rop3->rop3, d, s, &src_pos, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_image_unref(s);
|
||||||
|
|
||||||
|
GLCRecti dest;
|
||||||
|
GLCRecti src;
|
||||||
|
dest.x = bbox->left;
|
||||||
|
dest.y = bbox->top;
|
||||||
|
|
||||||
|
image.pixels = copy_opposite_image(canvas, image.pixels, pixman_image_get_stride(d),
|
||||||
|
pixman_image_get_height(d));
|
||||||
|
|
||||||
|
src.x = src.y = 0;
|
||||||
|
dest.width = src.width = image.width;
|
||||||
|
dest.height = src.height = image.height;
|
||||||
|
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
||||||
|
pixman_image_unref(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
GLCPath path;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
||||||
|
set_op(canvas, stroke->fore_mode);
|
||||||
|
set_brush(canvas, &stroke->brush);
|
||||||
|
|
||||||
|
if (stroke->attr.flags & SPICE_LINE_FLAGS_STYLED) {
|
||||||
|
WARN("SPICE_LINE_FLAGS_STYLED");
|
||||||
|
}
|
||||||
|
glc_set_line_width(canvas->glc, 1.0);
|
||||||
|
|
||||||
|
path = get_path(canvas, stroke->path);
|
||||||
|
glc_stroke_path(canvas->glc, path);
|
||||||
|
glc_path_destroy(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
GLCRect rect;
|
||||||
|
SpiceString *str;
|
||||||
|
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
||||||
|
|
||||||
|
if (!rect_is_empty(&text->back_area)) {
|
||||||
|
set_brush(canvas, &text->back_brush);
|
||||||
|
set_op(canvas, text->back_mode);
|
||||||
|
SET_GLC_RECT(&rect, bbox);
|
||||||
|
glc_fill_rect(canvas->glc, &rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
str = (SpiceString *)SPICE_GET_ADDRESS(text->str);
|
||||||
|
set_brush(canvas, &text->fore_brush);
|
||||||
|
set_op(canvas, text->fore_mode);
|
||||||
|
if (str->flags & SPICE_STRING_FLAGS_RASTER_A1) {
|
||||||
|
SpicePoint pos;
|
||||||
|
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 1, &pos);
|
||||||
|
_glc_fill_mask(canvas->glc, pos.x, pos.y,
|
||||||
|
pixman_image_get_width(mask),
|
||||||
|
pixman_image_get_height(mask),
|
||||||
|
pixman_image_get_stride(mask),
|
||||||
|
(uint8_t *)pixman_image_get_data(mask));
|
||||||
|
pixman_image_unref(mask);
|
||||||
|
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
|
||||||
|
SpicePoint pos;
|
||||||
|
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 4, &pos);
|
||||||
|
glc_fill_alpha(canvas->glc, pos.x, pos.y,
|
||||||
|
pixman_image_get_width(mask),
|
||||||
|
pixman_image_get_height(mask),
|
||||||
|
pixman_image_get_stride(mask),
|
||||||
|
(uint8_t *)pixman_image_get_data(mask));
|
||||||
|
|
||||||
|
pixman_image_unref(mask);
|
||||||
|
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
|
||||||
|
WARN("untested path A8 glyphs, doing nothing");
|
||||||
|
if (0) {
|
||||||
|
SpicePoint pos;
|
||||||
|
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 8, &pos);
|
||||||
|
glc_fill_alpha(canvas->glc, pos.x, pos.y,
|
||||||
|
pixman_image_get_width(mask),
|
||||||
|
pixman_image_get_height(mask),
|
||||||
|
pixman_image_get_stride(mask),
|
||||||
|
(uint8_t *)pixman_image_get_data(mask));
|
||||||
|
pixman_image_unref(mask);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WARN("untested path vector glyphs, doing nothing");
|
||||||
|
if (0) {
|
||||||
|
//draw_vector_str(canvas, str, &text->fore_brush, text->fore_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_clear(SpiceCanvas *spice_canvas)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
glc_clear(canvas->glc);
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
set_clip(canvas, bbox, clip);
|
||||||
|
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
||||||
|
glc_set_op(canvas->glc, GLC_OP_COPY);
|
||||||
|
glc_copy_pixels(canvas->glc, bbox->left, bbox->top, src_pos->x, src_pos->y,
|
||||||
|
bbox->right - bbox->left, bbox->bottom - bbox->top);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest, int dest_stride, const SpiceRect *area)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
GLCImage image;
|
||||||
|
|
||||||
|
ASSERT(dest_stride > 0);
|
||||||
|
image.format = GLC_IMAGE_RGB32;
|
||||||
|
image.height = area->bottom - area->top;
|
||||||
|
image.width = area->right - area->left;
|
||||||
|
image.pixels = dest;
|
||||||
|
image.stride = dest_stride;
|
||||||
|
glc_read_pixels(canvas->glc, area->left, area->top, &image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_group_start(SpiceCanvas *spice_canvas, QRegion *region)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
GLCRect *glc_rects;
|
||||||
|
GLCRect *now, *end;
|
||||||
|
int num_rect;
|
||||||
|
pixman_box32_t *rects;
|
||||||
|
|
||||||
|
canvas_base_group_start(spice_canvas, region);
|
||||||
|
|
||||||
|
rects = pixman_region32_rectangles(region, &num_rect);
|
||||||
|
|
||||||
|
glc_rects = spice_new(GLCRect, num_rect);
|
||||||
|
now = glc_rects;
|
||||||
|
end = glc_rects + num_rect;
|
||||||
|
|
||||||
|
for (; now < end; now++, rects++) {
|
||||||
|
SET_GLC_BOX(now, rects);
|
||||||
|
}
|
||||||
|
glc_mask_rects(canvas->glc, num_rect, glc_rects, GLC_MASK_B);
|
||||||
|
|
||||||
|
free(glc_rects);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_put_image(SpiceCanvas *spice_canvas, const SpiceRect *dest, const uint8_t *src_data,
|
||||||
|
uint32_t src_width, uint32_t src_height, int src_stride,
|
||||||
|
const QRegion *clip)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
GLCRecti src;
|
||||||
|
GLCRecti gldest;
|
||||||
|
GLCImage image;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
ASSERT(src_stride <= 0)
|
||||||
|
glc_clip_reset(canvas->glc);
|
||||||
|
|
||||||
|
if (clip) {
|
||||||
|
int num_rects;
|
||||||
|
pixman_box32_t *rects = pixman_region32_rectangles((pixman_region32_t *)clip,
|
||||||
|
&num_rects);
|
||||||
|
GLCRect rect;
|
||||||
|
if (num_rects == 0) {
|
||||||
|
rect.x = rect.y = rect.width = rect.height = 0;
|
||||||
|
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
|
||||||
|
} else {
|
||||||
|
SET_GLC_BOX(&rect, rects);
|
||||||
|
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
|
||||||
|
for (i = 1; i < num_rects; i++) {
|
||||||
|
SET_GLC_BOX(&rect, rects + i);
|
||||||
|
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_GLC_RECT(&gldest, dest);
|
||||||
|
src.x = src.y = 0;
|
||||||
|
src.width = src_width;
|
||||||
|
src.height = src_height;
|
||||||
|
|
||||||
|
image.format = GLC_IMAGE_RGB32;
|
||||||
|
image.width = src_width;
|
||||||
|
image.height = src_height;
|
||||||
|
src_stride = -src_stride;
|
||||||
|
image.stride = src_stride;
|
||||||
|
image.pixels = (uint8_t *)src_data - (src_height - 1) * src_stride;
|
||||||
|
image.pallet = NULL;
|
||||||
|
glc_draw_image(canvas->glc, &gldest, &src, &image, 0, 1);
|
||||||
|
|
||||||
|
glc_flush(canvas->glc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_group_end(SpiceCanvas *spice_canvas)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
|
||||||
|
canvas_base_group_end(spice_canvas);
|
||||||
|
glc_clear_mask(canvas->glc, GLC_MASK_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int need_init = 1;
|
||||||
|
static SpiceCanvasOps gl_canvas_ops;
|
||||||
|
|
||||||
|
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
|
||||||
|
#ifdef SW_CANVAS_CACHE
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
|
, SpicePaletteCache *palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
|
#endif
|
||||||
|
, SpiceImageSurfaces *surfaces
|
||||||
|
, SpiceGlzDecoder *glz_decoder
|
||||||
|
, SpiceJpegDecoder *jpeg_decoder
|
||||||
|
, SpiceZlibDecoder *zlib_decoder
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas;
|
||||||
|
int init_ok;
|
||||||
|
|
||||||
|
if (need_init) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
canvas = spice_new0(GLCanvas, 1);
|
||||||
|
|
||||||
|
if (!(canvas->glc = glc_create(width, height))) {
|
||||||
|
goto error_1;
|
||||||
|
}
|
||||||
|
canvas->private_data = NULL;
|
||||||
|
init_ok = canvas_base_init(&canvas->base, &gl_canvas_ops,
|
||||||
|
width, height, format
|
||||||
|
#ifdef SW_CANVAS_CACHE
|
||||||
|
, bits_cache
|
||||||
|
, palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, bits_cache
|
||||||
|
#endif
|
||||||
|
, surfaces
|
||||||
|
, glz_decoder
|
||||||
|
, jpeg_decoder
|
||||||
|
, zlib_decoder
|
||||||
|
);
|
||||||
|
if (!init_ok) {
|
||||||
|
goto error_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (SpiceCanvas *)canvas;
|
||||||
|
|
||||||
|
error_2:
|
||||||
|
glc_destroy(canvas->glc, 0);
|
||||||
|
error_1:
|
||||||
|
free(canvas);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl_canvas_set_textures_lost(SpiceCanvas *spice_canvas,
|
||||||
|
int textures_lost)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
|
||||||
|
canvas->textures_lost = textures_lost;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gl_canvas_destroy(SpiceCanvas *spice_canvas)
|
||||||
|
{
|
||||||
|
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
||||||
|
|
||||||
|
if (!canvas) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
canvas_base_destroy(&canvas->base);
|
||||||
|
glc_destroy(canvas->glc, canvas->textures_lost);
|
||||||
|
free(canvas->private_data);
|
||||||
|
free(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl_canvas_init(void) //unsafe global function
|
||||||
|
{
|
||||||
|
if (!need_init) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
need_init = 0;
|
||||||
|
|
||||||
|
canvas_base_init_ops(&gl_canvas_ops);
|
||||||
|
gl_canvas_ops.draw_fill = gl_canvas_draw_fill;
|
||||||
|
gl_canvas_ops.draw_copy = gl_canvas_draw_copy;
|
||||||
|
gl_canvas_ops.draw_opaque = gl_canvas_draw_opaque;
|
||||||
|
gl_canvas_ops.copy_bits = gl_canvas_copy_bits;
|
||||||
|
gl_canvas_ops.draw_text = gl_canvas_draw_text;
|
||||||
|
gl_canvas_ops.draw_stroke = gl_canvas_draw_stroke;
|
||||||
|
gl_canvas_ops.draw_rop3 = gl_canvas_draw_rop3;
|
||||||
|
gl_canvas_ops.draw_blend = gl_canvas_draw_blend;
|
||||||
|
gl_canvas_ops.draw_blackness = gl_canvas_draw_blackness;
|
||||||
|
gl_canvas_ops.draw_whiteness = gl_canvas_draw_whiteness;
|
||||||
|
gl_canvas_ops.draw_invers = gl_canvas_draw_invers;
|
||||||
|
gl_canvas_ops.draw_transparent = gl_canvas_draw_transparent;
|
||||||
|
gl_canvas_ops.draw_alpha_blend = gl_canvas_draw_alpha_blend;
|
||||||
|
gl_canvas_ops.put_image = gl_canvas_put_image;
|
||||||
|
gl_canvas_ops.clear = gl_canvas_clear;
|
||||||
|
gl_canvas_ops.read_bits = gl_canvas_read_bits;
|
||||||
|
gl_canvas_ops.group_start = gl_canvas_group_start;
|
||||||
|
gl_canvas_ops.group_end = gl_canvas_group_end;
|
||||||
|
gl_canvas_ops.destroy = gl_canvas_destroy;
|
||||||
|
|
||||||
|
rop3_init();
|
||||||
|
}
|
||||||
53
common/gl_canvas.h
Normal file
53
common/gl_canvas.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "glc.h"
|
||||||
|
#include "canvas_base.h"
|
||||||
|
#include "region.h"
|
||||||
|
|
||||||
|
#ifndef SPICE_CANVAS_INTERNAL
|
||||||
|
#error "This header shouldn't be included directly"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _H__GL_CANVAS
|
||||||
|
#define _H__GL_CANVAS
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
|
||||||
|
#ifdef SW_CANVAS_CACHE
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
|
, SpicePaletteCache *palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
|
#endif
|
||||||
|
, SpiceImageSurfaces *surfaces
|
||||||
|
, SpiceGlzDecoder *glz_decoder
|
||||||
|
, SpiceJpegDecoder *jpeg_decoder
|
||||||
|
, SpiceZlibDecoder *zlib_decoder
|
||||||
|
);
|
||||||
|
void gl_canvas_set_textures_lost(SpiceCanvas *canvas, int textures_lost);
|
||||||
|
void gl_canvas_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
61
common/gl_utils.h
Normal file
61
common/gl_utils.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GL_UTILS_H
|
||||||
|
#define GL_UTILS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RED_DEBUG
|
||||||
|
#define GLC_ERROR_TEST_FLUSH { \
|
||||||
|
GLenum gl_err; glFlush(); \
|
||||||
|
if ((gl_err = glGetError()) != GL_NO_ERROR) { \
|
||||||
|
printf("%s[%d]: opengl error: %s\n", __FUNCTION__, __LINE__, \
|
||||||
|
gluErrorString(gl_err)); \
|
||||||
|
abort(); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GLC_ERROR_TEST_FINISH { \
|
||||||
|
GLenum gl_err; glFinish(); \
|
||||||
|
if ((gl_err = glGetError()) != GL_NO_ERROR) { \
|
||||||
|
printf("%s[%d]: opengl error: %s\n", __FUNCTION__, __LINE__, \
|
||||||
|
gluErrorString(gl_err)); \
|
||||||
|
abort(); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define GLC_ERROR_TEST_FLUSH ;
|
||||||
|
|
||||||
|
#define GLC_ERROR_TEST_FINISH ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "bitops.h"
|
||||||
|
|
||||||
|
#define find_msb spice_bit_find_msb
|
||||||
|
#define gl_get_to_power_two spice_bit_next_pow2
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
1513
common/glc.c
Normal file
1513
common/glc.c
Normal file
File diff suppressed because it is too large
Load Diff
167
common/glc.h
Normal file
167
common/glc.h
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _H_GL_CANVASE
|
||||||
|
#define _H_GL_CANVASE
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void * GLCCtx;
|
||||||
|
typedef void * GLCPattern;
|
||||||
|
typedef void * GLCPath;
|
||||||
|
|
||||||
|
typedef struct GLCRect {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double width;
|
||||||
|
double height;
|
||||||
|
} GLCRect;
|
||||||
|
|
||||||
|
typedef struct GLCRecti {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
} GLCRecti;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GLC_IMAGE_RGB32,
|
||||||
|
GLC_IMAGE_ARGB32,
|
||||||
|
} GLCImageFormat;
|
||||||
|
|
||||||
|
typedef struct GLCPImage {
|
||||||
|
GLCImageFormat format;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int stride;
|
||||||
|
uint8_t *pixels;
|
||||||
|
uint32_t *pallet;
|
||||||
|
} GLCImage;
|
||||||
|
|
||||||
|
GLCPattern glc_pattern_create(GLCCtx glc, int x_orign, int y_orign, const GLCImage *image);
|
||||||
|
void glc_pattern_set(GLCPattern pattern, int x_orign, int y_orign, const GLCImage *image);
|
||||||
|
void glc_pattern_destroy(GLCPattern pattern);
|
||||||
|
|
||||||
|
void glc_path_move_to(GLCPath path, double x, double y);
|
||||||
|
void glc_path_line_to(GLCPath path, double x, double y);
|
||||||
|
void glc_path_curve_to(GLCPath path, double p1_x, double p1_y, double p2_x, double p2_y,
|
||||||
|
double p3_x, double p3_y);
|
||||||
|
void glc_path_rel_move_to(GLCPath path, double x, double y);
|
||||||
|
void glc_path_rel_line_to(GLCPath path, double x, double y);
|
||||||
|
void glc_path_rel_curve_to(GLCPath path, double p1_x, double p1_y, double p2_x, double p2_y,
|
||||||
|
double p3_x, double p3_y);
|
||||||
|
void glc_path_close(GLCPath path);
|
||||||
|
|
||||||
|
void glc_path_cleare(GLCPath);
|
||||||
|
GLCPath glc_path_create(GLCCtx glc);
|
||||||
|
void glc_path_destroy(GLCPath path);
|
||||||
|
|
||||||
|
void glc_set_rgb(GLCCtx glc, double red, double green, double blue);
|
||||||
|
void glc_set_rgba(GLCCtx glc, double red, double green, double blue, double alpha);
|
||||||
|
void glc_set_pattern(GLCCtx glc, GLCPattern pattern);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GLC_OP_CLEAR = 0x1500,
|
||||||
|
GLC_OP_SET = 0x150F,
|
||||||
|
GLC_OP_COPY = 0x1503,
|
||||||
|
GLC_OP_COPY_INVERTED = 0x150C,
|
||||||
|
GLC_OP_NOOP = 0x1505,
|
||||||
|
GLC_OP_INVERT = 0x150A,
|
||||||
|
GLC_OP_AND = 0x1501,
|
||||||
|
GLC_OP_NAND = 0x150E,
|
||||||
|
GLC_OP_OR = 0x1507,
|
||||||
|
GLC_OP_NOR = 0x1508,
|
||||||
|
GLC_OP_XOR = 0x1506,
|
||||||
|
GLC_OP_EQUIV = 0x1509,
|
||||||
|
GLC_OP_AND_REVERSE = 0x1502,
|
||||||
|
GLC_OP_AND_INVERTED = 0x1504,
|
||||||
|
GLC_OP_OR_REVERSE = 0x150B,
|
||||||
|
GLC_OP_OR_INVERTED = 0x150D,
|
||||||
|
} GLCOp;
|
||||||
|
|
||||||
|
void glc_set_op(GLCCtx glc, GLCOp op);
|
||||||
|
void glc_set_alpha_factor(GLCCtx glc, double alpah);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GLC_FILL_MODE_WINDING_ODD,
|
||||||
|
GLC_FILL_MODE_WINDING_NONZERO,
|
||||||
|
} GLCFillMode;
|
||||||
|
|
||||||
|
void glc_set_fill_mode(GLCCtx glc, GLCFillMode mode);
|
||||||
|
void glc_set_line_width(GLCCtx glc, double width);
|
||||||
|
void glc_set_line_end_cap(GLCCtx glc, int style);
|
||||||
|
void glc_set_line_join(GLCCtx glc, int style);
|
||||||
|
void glc_set_miter_limit(GLCCtx glc, int limit);
|
||||||
|
void glc_set_line_dash(GLCCtx glc, const double *dashes, int num_dashes, double offset);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GLC_MASK_A,
|
||||||
|
GLC_MASK_B,
|
||||||
|
} GLCMaskID;
|
||||||
|
|
||||||
|
void glc_set_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height,
|
||||||
|
int stride, const uint8_t *bitmap, GLCMaskID id);
|
||||||
|
void glc_mask_rects(GLCCtx glc, int num_rect, GLCRect *rects, GLCMaskID id);
|
||||||
|
void glc_clear_mask(GLCCtx glc, GLCMaskID id);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GLC_CLIP_OP_SET,
|
||||||
|
GLC_CLIP_OP_OR,
|
||||||
|
GLC_CLIP_OP_AND,
|
||||||
|
GLC_CLIP_OP_EXCLUDE,
|
||||||
|
} GLCClipOp;
|
||||||
|
|
||||||
|
void glc_clip_rect(GLCCtx glc, const GLCRect *rect, GLCClipOp op);
|
||||||
|
void glc_clip_path(GLCCtx glc, GLCPath path, GLCClipOp op);
|
||||||
|
void glc_clip_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
|
||||||
|
const uint8_t *bitmap, GLCClipOp op);
|
||||||
|
void glc_clip_reset(GLCCtx glc);
|
||||||
|
|
||||||
|
void glc_fill_rect(GLCCtx glc, const GLCRect *rect);
|
||||||
|
void glc_fill_path(GLCCtx glc, GLCPath path);
|
||||||
|
void _glc_fill_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
|
||||||
|
const uint8_t *bitmap);
|
||||||
|
void glc_fill_alpha(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
|
||||||
|
const uint8_t *alpha_mask);
|
||||||
|
|
||||||
|
void glc_stroke_rect(GLCCtx glc, const GLCRect *rect);
|
||||||
|
void glc_stroke_path(GLCCtx glc, GLCPath path);
|
||||||
|
|
||||||
|
void glc_draw_image(GLCCtx glc, const GLCRecti *dest, const GLCRecti *src, const GLCImage *image,
|
||||||
|
int scale_mode, double alpha);
|
||||||
|
|
||||||
|
void glc_copy_pixels(GLCCtx glc, int x_dest, int y_dest, int x_src, int y_src, int width,
|
||||||
|
int height);
|
||||||
|
void glc_read_pixels(GLCCtx glc, int x, int y, GLCImage *image);
|
||||||
|
|
||||||
|
void glc_flush(GLCCtx glc);
|
||||||
|
void glc_clear(GLCCtx glc);
|
||||||
|
GLCCtx glc_create(int width, int height);
|
||||||
|
void glc_destroy(GLCCtx glc, int textures_lost);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -45,7 +45,9 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
@ -82,7 +84,7 @@ typedef struct lineGC *GCPtr;
|
|||||||
#define miWideDash spice_canvas_wide_dash_line
|
#define miWideDash spice_canvas_wide_dash_line
|
||||||
#define miWideLine spice_canvas_wide_line
|
#define miWideLine spice_canvas_wide_line
|
||||||
|
|
||||||
static inline int ICEIL (double x)
|
static INLINE int ICEIL (double x)
|
||||||
{
|
{
|
||||||
int _cTmp = (int)x;
|
int _cTmp = (int)x;
|
||||||
return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp + 1;
|
return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp + 1;
|
||||||
@ -410,7 +412,7 @@ miStepDash (int dist, /* distance to step */
|
|||||||
totallen = 0;
|
totallen = 0;
|
||||||
for (i = 0; i < numInDashList; i++)
|
for (i = 0; i < numInDashList; i++)
|
||||||
totallen += pDash[i];
|
totallen += pDash[i];
|
||||||
if (totallen > 0 && totallen <= dist)
|
if (totallen <= dist)
|
||||||
dist = dist % totallen;
|
dist = dist % totallen;
|
||||||
while (dist >= pDash[dashIndex]) {
|
while (dist >= pDash[dashIndex]) {
|
||||||
dist -= pDash[dashIndex];
|
dist -= pDash[dashIndex];
|
||||||
@ -804,14 +806,14 @@ miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
|
|||||||
newwidths = xrealloc (newspans->widths,
|
newwidths = xrealloc (newspans->widths,
|
||||||
ysizes[index] * sizeof (int));
|
ysizes[index] * sizeof (int));
|
||||||
if (!newpoints || !newwidths) {
|
if (!newpoints || !newwidths) {
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ylength; i++) {
|
for (i = 0; i < ylength; i++) {
|
||||||
xfree (yspans[i].points);
|
xfree (yspans[i].points);
|
||||||
xfree (yspans[i].widths);
|
xfree (yspans[i].widths);
|
||||||
}
|
}
|
||||||
xfree (yspans);
|
xfree (yspans);
|
||||||
xfree (ysizes);
|
xfree (ysizes);
|
||||||
xfree (newpoints);
|
|
||||||
xfree (newwidths);
|
|
||||||
miDisposeSpanGroup (spanGroup);
|
miDisposeSpanGroup (spanGroup);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -834,6 +836,8 @@ miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
|
|||||||
points = (DDXPointRec*)xalloc (count * sizeof (DDXPointRec));
|
points = (DDXPointRec*)xalloc (count * sizeof (DDXPointRec));
|
||||||
widths = (int *)xalloc (count * sizeof (int));
|
widths = (int *)xalloc (count * sizeof (int));
|
||||||
if (!points || !widths) {
|
if (!points || !widths) {
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ylength; i++) {
|
for (i = 0; i < ylength; i++) {
|
||||||
xfree (yspans[i].points);
|
xfree (yspans[i].points);
|
||||||
xfree (yspans[i].widths);
|
xfree (yspans[i].widths);
|
||||||
@ -925,7 +929,7 @@ end of the line, we will find the largest number of Y steps that
|
|||||||
satisfies the inequality. In that case, since we are representing
|
satisfies the inequality. In that case, since we are representing
|
||||||
the Y steps as (dy - N), we will actually want to solve for the
|
the Y steps as (dy - N), we will actually want to solve for the
|
||||||
smallest N in that equation.
|
smallest N in that equation.
|
||||||
|
|
||||||
Case 1: X major, starting X coordinate moved by M steps
|
Case 1: X major, starting X coordinate moved by M steps
|
||||||
|
|
||||||
-2dx <= 2Mdy - 2Ndx - dx - B < 0
|
-2dx <= 2Mdy - 2Ndx - dx - B < 0
|
||||||
@ -973,7 +977,7 @@ steps, so we want the highest N, so we use the < inequality:
|
|||||||
= floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
|
= floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
|
||||||
= floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
|
= floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
|
||||||
= floor((2Mdy + dx + B - 1) / 2dx)
|
= floor((2Mdy + dx + B - 1) / 2dx)
|
||||||
|
|
||||||
Case 3: Y major, starting X coordinate moved by M steps
|
Case 3: Y major, starting X coordinate moved by M steps
|
||||||
|
|
||||||
-2dy <= 2Ndx - 2Mdy - dy - B < 0
|
-2dy <= 2Ndx - 2Mdy - dy - B < 0
|
||||||
@ -1019,7 +1023,7 @@ Same analysis as Case 4, but we want the smallest number of Y steps
|
|||||||
which means the largest N, so we use the <= inequality:
|
which means the largest N, so we use the <= inequality:
|
||||||
|
|
||||||
N = floor((2Mdy + dy - B) / 2dx)
|
N = floor((2Mdy + dy - B) / 2dx)
|
||||||
|
|
||||||
Now let's try the Y coordinates, we have the same 4 cases.
|
Now let's try the Y coordinates, we have the same 4 cases.
|
||||||
|
|
||||||
Case 5: X major, starting Y coordinate moved by N steps
|
Case 5: X major, starting Y coordinate moved by N steps
|
||||||
@ -1064,7 +1068,7 @@ Same derivations as Case 6, but we want the smallest # of X steps
|
|||||||
which means the largest M, so use the <= inequality:
|
which means the largest M, so use the <= inequality:
|
||||||
|
|
||||||
M = floor((2Ndx + dx - B) / 2dy)
|
M = floor((2Ndx + dx - B) / 2dy)
|
||||||
|
|
||||||
Case 7: Y major, starting Y coordinate moved by N steps
|
Case 7: Y major, starting Y coordinate moved by N steps
|
||||||
|
|
||||||
-2dy <= 2Ndx - 2Mdy - dy - B < 0
|
-2dy <= 2Ndx - 2Mdy - dy - B < 0
|
||||||
@ -1109,7 +1113,7 @@ steps which means the largest M, so we use the < inequality:
|
|||||||
= floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
|
= floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
|
||||||
= floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
|
= floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
|
||||||
= floor((2Ndx + dy + B - 1) / 2dy)
|
= floor((2Ndx + dy + B - 1) / 2dy)
|
||||||
|
|
||||||
So, our equations are:
|
So, our equations are:
|
||||||
|
|
||||||
1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
|
1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
|
||||||
@ -1822,7 +1826,7 @@ miFillRectPolyHelper (GCPtr pGC, Boolean foreground, SpanDataPtr spanData, int x
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
miPolyBuildEdge (SPICE_GNUC_UNUSED double x0, double y0, double k, /* x0 * dy - y0 * dx */
|
miPolyBuildEdge (double x0, double y0, double k, /* x0 * dy - y0 * dx */
|
||||||
int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge)
|
int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge)
|
||||||
{
|
{
|
||||||
int x, y, e;
|
int x, y, e;
|
||||||
@ -1833,6 +1837,15 @@ miPolyBuildEdge (SPICE_GNUC_UNUSED double x0, double y0, double k, /* x0 * dy -
|
|||||||
dx = -dx;
|
dx = -dx;
|
||||||
k = -k;
|
k = -k;
|
||||||
}
|
}
|
||||||
|
#ifdef NOTDEF
|
||||||
|
{
|
||||||
|
double realk, kerror;
|
||||||
|
realk = x0 * dy - y0 * dx;
|
||||||
|
kerror = Fabs (realk - k);
|
||||||
|
if (kerror > .1)
|
||||||
|
printf ("realk: %g k: %g\n", realk, k);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
y = ICEIL (y0);
|
y = ICEIL (y0);
|
||||||
xady = ICEIL (k) + y * dx;
|
xady = ICEIL (k) + y * dx;
|
||||||
|
|
||||||
@ -1957,11 +1970,7 @@ miPolyBuildPoly (PolyVertexPtr vertices,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
miLineOnePoint (GCPtr pGC,
|
miLineOnePoint (GCPtr pGC, Boolean foreground, SpanDataPtr spanData, int x, int y)
|
||||||
Boolean foreground,
|
|
||||||
SPICE_GNUC_UNUSED SpanDataPtr spanData,
|
|
||||||
int x,
|
|
||||||
int y)
|
|
||||||
{
|
{
|
||||||
DDXPointRec pt;
|
DDXPointRec pt;
|
||||||
int wid;
|
int wid;
|
||||||
@ -2421,7 +2430,7 @@ miLineArc (GCPtr pGC,
|
|||||||
int xorgi = 0, yorgi = 0;
|
int xorgi = 0, yorgi = 0;
|
||||||
Spans spanRec;
|
Spans spanRec;
|
||||||
int n;
|
int n;
|
||||||
PolyEdgeRec edge1 = { 0 }, edge2 = { 0 };
|
PolyEdgeRec edge1, edge2;
|
||||||
int edgey1, edgey2;
|
int edgey1, edgey2;
|
||||||
Boolean edgeleft1, edgeleft2;
|
Boolean edgeleft1, edgeleft2;
|
||||||
|
|
||||||
@ -2492,18 +2501,13 @@ miLineArc (GCPtr pGC,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
miLineProjectingCap (GCPtr pGC,
|
miLineProjectingCap (GCPtr pGC, Boolean foreground,
|
||||||
Boolean foreground,
|
SpanDataPtr spanData, LineFacePtr face, Boolean isLeft,
|
||||||
SpanDataPtr spanData,
|
double xorg, double yorg, Boolean isInt)
|
||||||
LineFacePtr face,
|
|
||||||
Boolean isLeft,
|
|
||||||
SPICE_GNUC_UNUSED double xorg,
|
|
||||||
SPICE_GNUC_UNUSED double yorg,
|
|
||||||
Boolean isInt)
|
|
||||||
{
|
{
|
||||||
int xorgi = 0, yorgi = 0;
|
int xorgi = 0, yorgi = 0;
|
||||||
int lw;
|
int lw;
|
||||||
PolyEdgeRec lefts[4], rights[4];
|
PolyEdgeRec lefts[2], rights[2];
|
||||||
int lefty, righty, topy, bottomy;
|
int lefty, righty, topy, bottomy;
|
||||||
PolyEdgePtr left, right;
|
PolyEdgePtr left, right;
|
||||||
PolyEdgePtr top, bottom;
|
PolyEdgePtr top, bottom;
|
||||||
@ -2661,7 +2665,7 @@ miWideSegment (GCPtr pGC,
|
|||||||
PolyEdgePtr top, bottom;
|
PolyEdgePtr top, bottom;
|
||||||
int lefty, righty, topy, bottomy;
|
int lefty, righty, topy, bottomy;
|
||||||
int signdx;
|
int signdx;
|
||||||
PolyEdgeRec lefts[4], rights[4];
|
PolyEdgeRec lefts[2], rights[2];
|
||||||
LineFacePtr tface;
|
LineFacePtr tface;
|
||||||
int lw = pGC->lineWidth;
|
int lw = pGC->lineWidth;
|
||||||
|
|
||||||
@ -2976,9 +2980,9 @@ miWideDashSegment (GCPtr pGC,
|
|||||||
double L, l;
|
double L, l;
|
||||||
double k;
|
double k;
|
||||||
PolyVertexRec vertices[4];
|
PolyVertexRec vertices[4];
|
||||||
PolyVertexRec saveRight = { 0, 0 }, saveBottom;
|
PolyVertexRec saveRight = { 0 }, saveBottom;
|
||||||
PolySlopeRec slopes[4];
|
PolySlopeRec slopes[4];
|
||||||
PolyEdgeRec left[4], right[4];
|
PolyEdgeRec left[2], right[2];
|
||||||
LineFaceRec lcapFace, rcapFace;
|
LineFaceRec lcapFace, rcapFace;
|
||||||
int nleft, nright;
|
int nleft, nright;
|
||||||
int h;
|
int h;
|
||||||
|
|||||||
@ -46,17 +46,17 @@ SOFTWARE.
|
|||||||
|
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_LINES
|
#ifndef LINES_H
|
||||||
#define H_SPICE_COMMON_LINES
|
#define LINES_H
|
||||||
|
|
||||||
|
#include <pixman_utils.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#include "pixman_utils.h"
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct lineGC lineGC;
|
typedef struct lineGC lineGC;
|
||||||
|
|
||||||
@ -131,6 +131,8 @@ extern int spice_canvas_clip_spans(pixman_region32_t *clip_region,
|
|||||||
int *new_widths,
|
int *new_widths,
|
||||||
int sorted);
|
int sorted);
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_LINES
|
#endif /* LINES_H */
|
||||||
|
|||||||
71
common/log.c
71
common/log.c
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2012-2015 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <common/recorder.h>
|
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
#include "backtrace.h"
|
|
||||||
|
|
||||||
#define G_LOG_DOMAIN "Spice"
|
|
||||||
|
|
||||||
SPICE_CONSTRUCTOR_FUNC(spice_log_init)
|
|
||||||
{
|
|
||||||
recorder_dump_on_common_signals(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
G_GNUC_PRINTF(5, 0)
|
|
||||||
static void spice_logv(const char *log_domain,
|
|
||||||
GLogLevelFlags log_level,
|
|
||||||
const char *strloc,
|
|
||||||
const char *function,
|
|
||||||
const char *format,
|
|
||||||
va_list args)
|
|
||||||
{
|
|
||||||
GString *log_msg;
|
|
||||||
|
|
||||||
log_msg = g_string_new(NULL);
|
|
||||||
if (strloc && function) {
|
|
||||||
g_string_append_printf(log_msg, "%s:%s: ", strloc, function);
|
|
||||||
}
|
|
||||||
if (format) {
|
|
||||||
g_string_append_vprintf(log_msg, format, args);
|
|
||||||
}
|
|
||||||
g_log(log_domain, log_level, "%s", log_msg->str);
|
|
||||||
g_string_free(log_msg, TRUE);
|
|
||||||
|
|
||||||
if ((log_level & G_LOG_LEVEL_CRITICAL) != 0) {
|
|
||||||
spice_backtrace();
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void spice_log(GLogLevelFlags log_level,
|
|
||||||
const char *strloc,
|
|
||||||
const char *function,
|
|
||||||
const char *format,
|
|
||||||
...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start (args, format);
|
|
||||||
spice_logv (G_LOG_DOMAIN, log_level, strloc, function, format, args);
|
|
||||||
va_end (args);
|
|
||||||
}
|
|
||||||
110
common/log.h
110
common/log.h
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2012 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_LOG
|
|
||||||
#define H_SPICE_COMMON_LOG
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#include "macros.h"
|
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
|
||||||
|
|
||||||
#ifdef SPICE_LOG_DOMAIN
|
|
||||||
#error Do not use obsolete SPICE_LOG_DOMAIN macro, is currently unused
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SPICE_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__)
|
|
||||||
|
|
||||||
void spice_log(GLogLevelFlags log_level,
|
|
||||||
const char *strloc,
|
|
||||||
const char *function,
|
|
||||||
const char *format,
|
|
||||||
...) G_GNUC_PRINTF(4, 5);
|
|
||||||
|
|
||||||
/* FIXME: name is misleading, this aborts.. */
|
|
||||||
#define spice_return_if_fail(x) G_STMT_START { \
|
|
||||||
if G_LIKELY(x) { } else { \
|
|
||||||
spice_critical("condition `%s' failed", #x); \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
/* FIXME: name is misleading, this aborts.. */
|
|
||||||
#define spice_return_val_if_fail(x, val) G_STMT_START { \
|
|
||||||
if G_LIKELY(x) { } else { \
|
|
||||||
spice_critical("condition `%s' failed", #x); \
|
|
||||||
return (val); \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define spice_warn_if_reached() G_STMT_START { \
|
|
||||||
spice_log(G_LOG_LEVEL_WARNING, SPICE_STRLOC, __FUNCTION__, "should not be reached"); \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define spice_info(...) G_STMT_START { \
|
|
||||||
spice_log(G_LOG_LEVEL_INFO, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define spice_debug(...) G_STMT_START { \
|
|
||||||
spice_log(G_LOG_LEVEL_DEBUG, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define spice_warning(...) G_STMT_START { \
|
|
||||||
spice_log(G_LOG_LEVEL_WARNING, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define spice_critical(...) G_STMT_START { \
|
|
||||||
spice_log(G_LOG_LEVEL_CRITICAL, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
|
||||||
SPICE_UNREACHABLE; \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define spice_error(...) G_STMT_START { \
|
|
||||||
spice_log(G_LOG_LEVEL_ERROR, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
|
||||||
SPICE_UNREACHABLE; \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define spice_warn_if_fail(x) G_STMT_START { \
|
|
||||||
if G_LIKELY(x) { } else { \
|
|
||||||
spice_warning("condition `%s' failed", #x); \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define spice_assert(x) G_STMT_START { \
|
|
||||||
if G_LIKELY(x) { } else { \
|
|
||||||
spice_error("assertion `%s' failed", #x); \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#if ENABLE_EXTRA_CHECKS
|
|
||||||
enum { spice_extra_checks = 1 };
|
|
||||||
#else
|
|
||||||
enum { spice_extra_checks = 0 };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define spice_extra_assert(x) G_STMT_START { \
|
|
||||||
if (!spice_extra_checks || G_LIKELY(x)) { } else { \
|
|
||||||
spice_error("assertion `%s' failed", #x); \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
SPICE_END_DECLS
|
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_LOG
|
|
||||||
183
common/lz.c
183
common/lz.c
@ -43,16 +43,29 @@
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "lz.h"
|
#include "lz.h"
|
||||||
|
|
||||||
|
#define DEBUG
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
|
||||||
|
#define ASSERT(usr, x) \
|
||||||
|
if (!(x)) (usr)->error(usr, "%s: ASSERT %s failed\n", __FUNCTION__, #x);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ASSERT(usr, x)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#define HASH_LOG 13
|
#define HASH_LOG 13
|
||||||
#define HASH_SIZE (1 << HASH_LOG)
|
#define HASH_SIZE (1 << HASH_LOG)
|
||||||
#define HASH_MASK (HASH_SIZE - 1)
|
#define HASH_MASK (HASH_SIZE - 1)
|
||||||
|
|
||||||
/* Maximum image size, mainly to avoid possible integer overflows */
|
|
||||||
#define SPICE_MAX_IMAGE_SIZE (1024 * 1024 * 1024 - 1)
|
|
||||||
|
|
||||||
typedef struct LzImageSegment LzImageSegment;
|
typedef struct LzImageSegment LzImageSegment;
|
||||||
struct LzImageSegment {
|
struct LzImageSegment {
|
||||||
@ -89,6 +102,7 @@ typedef struct Encoder {
|
|||||||
// (2) a pointer to the first byte in the segment that matches the word
|
// (2) a pointer to the first byte in the segment that matches the word
|
||||||
HashEntry htab[HASH_SIZE];
|
HashEntry htab[HASH_SIZE];
|
||||||
|
|
||||||
|
uint8_t *io_start;
|
||||||
uint8_t *io_now;
|
uint8_t *io_now;
|
||||||
uint8_t *io_end;
|
uint8_t *io_end;
|
||||||
size_t io_bytes_count;
|
size_t io_bytes_count;
|
||||||
@ -99,7 +113,7 @@ typedef struct Encoder {
|
|||||||
/****************************************************/
|
/****************************************************/
|
||||||
/* functions for managing the pool of image segments*/
|
/* functions for managing the pool of image segments*/
|
||||||
/****************************************************/
|
/****************************************************/
|
||||||
static inline LzImageSegment *lz_alloc_image_seg(Encoder *encoder);
|
static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder);
|
||||||
static void lz_reset_image_seg(Encoder *encoder);
|
static void lz_reset_image_seg(Encoder *encoder);
|
||||||
static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
|
static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
|
||||||
unsigned int num_first_lines);
|
unsigned int num_first_lines);
|
||||||
@ -107,7 +121,7 @@ static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
|
|||||||
|
|
||||||
// return a free image segment if one exists. Make allocation if needed. adds it to the
|
// return a free image segment if one exists. Make allocation if needed. adds it to the
|
||||||
// tail of the image segments lists
|
// tail of the image segments lists
|
||||||
static inline LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
|
static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
|
||||||
{
|
{
|
||||||
LzImageSegment *ret;
|
LzImageSegment *ret;
|
||||||
|
|
||||||
@ -134,7 +148,7 @@ static inline LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// adding seg to the head of free segments (lz_reset_image_seg removes it from used ones)
|
// adding seg to the head of free segments (lz_reset_image_seg removes it from used ones)
|
||||||
static inline void __lz_free_image_seg(Encoder *encoder, LzImageSegment *seg)
|
static INLINE void __lz_free_image_seg(Encoder *encoder, LzImageSegment *seg)
|
||||||
{
|
{
|
||||||
seg->next = encoder->free_image_segs;
|
seg->next = encoder->free_image_segs;
|
||||||
encoder->free_image_segs = seg;
|
encoder->free_image_segs = seg;
|
||||||
@ -170,7 +184,7 @@ static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
|
|||||||
uint8_t* lines = first_lines;
|
uint8_t* lines = first_lines;
|
||||||
int row;
|
int row;
|
||||||
|
|
||||||
spice_return_val_if_fail(!encoder->head_image_segs, FALSE);
|
ASSERT(encoder->usr, !encoder->head_image_segs);
|
||||||
|
|
||||||
image_seg = lz_alloc_image_seg(encoder);
|
image_seg = lz_alloc_image_seg(encoder);
|
||||||
if (!image_seg) {
|
if (!image_seg) {
|
||||||
@ -210,7 +224,7 @@ error_1:
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Handling encoding and decoding of a byte
|
* Handling encoding and decoding of a byte
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
static inline int more_io_bytes(Encoder *encoder)
|
static INLINE int more_io_bytes(Encoder *encoder)
|
||||||
{
|
{
|
||||||
uint8_t *io_ptr;
|
uint8_t *io_ptr;
|
||||||
int num_io_bytes = encoder->usr->more_space(encoder->usr, &io_ptr);
|
int num_io_bytes = encoder->usr->more_space(encoder->usr, &io_ptr);
|
||||||
@ -220,20 +234,20 @@ static inline int more_io_bytes(Encoder *encoder)
|
|||||||
return num_io_bytes;
|
return num_io_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void encode(Encoder *encoder, uint8_t byte)
|
static INLINE void encode(Encoder *encoder, uint8_t byte)
|
||||||
{
|
{
|
||||||
if (encoder->io_now == encoder->io_end) {
|
if (encoder->io_now == encoder->io_end) {
|
||||||
if (more_io_bytes(encoder) <= 0) {
|
if (more_io_bytes(encoder) <= 0) {
|
||||||
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
|
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
spice_return_if_fail(encoder->io_now);
|
ASSERT(encoder->usr, encoder->io_now);
|
||||||
}
|
}
|
||||||
|
|
||||||
spice_return_if_fail(encoder->io_now < encoder->io_end);
|
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
|
||||||
*(encoder->io_now++) = byte;
|
*(encoder->io_now++) = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void encode_32(Encoder *encoder, unsigned int word)
|
static INLINE void encode_32(Encoder *encoder, unsigned int word)
|
||||||
{
|
{
|
||||||
encode(encoder, (uint8_t)(word >> 24));
|
encode(encoder, (uint8_t)(word >> 24));
|
||||||
encode(encoder, (uint8_t)(word >> 16) & 0x0000ff);
|
encode(encoder, (uint8_t)(word >> 16) & 0x0000ff);
|
||||||
@ -241,32 +255,37 @@ static inline void encode_32(Encoder *encoder, unsigned int word)
|
|||||||
encode(encoder, (uint8_t)(word & 0x0000ff));
|
encode(encoder, (uint8_t)(word & 0x0000ff));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void encode_copy_count(Encoder *encoder, uint8_t copy_count)
|
static INLINE void encode_copy_count(Encoder *encoder, uint8_t copy_count)
|
||||||
{
|
{
|
||||||
encode(encoder, copy_count);
|
encode(encoder, copy_count);
|
||||||
encoder->io_last_copy = encoder->io_now - 1; // io_now cannot be the first byte of the buffer
|
encoder->io_last_copy = encoder->io_now - 1; // io_now cannot be the first byte of the buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void update_copy_count(Encoder *encoder, uint8_t copy_count)
|
static INLINE void update_copy_count(Encoder *encoder, uint8_t copy_count)
|
||||||
{
|
{
|
||||||
spice_return_if_fail(encoder->io_last_copy);
|
ASSERT(encoder->usr, encoder->io_last_copy);
|
||||||
*(encoder->io_last_copy) = copy_count;
|
*(encoder->io_last_copy) = copy_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INLINE void encode_level(Encoder *encoder, uint8_t level_code)
|
||||||
|
{
|
||||||
|
*(encoder->io_start) |= level_code;
|
||||||
|
}
|
||||||
|
|
||||||
// decrease the io ptr by 1
|
// decrease the io ptr by 1
|
||||||
static inline void compress_output_prev(Encoder *encoder)
|
static INLINE void compress_output_prev(Encoder *encoder)
|
||||||
{
|
{
|
||||||
// io_now cannot be the first byte of the buffer
|
// io_now cannot be the first byte of the buffer
|
||||||
encoder->io_now--;
|
encoder->io_now--;
|
||||||
// the function should be called only when copy count is written unnecessarily by lz_compress
|
// the function should be called only when copy count is written unnecessarily by lz_compress
|
||||||
spice_return_if_fail(encoder->io_now == encoder->io_last_copy);
|
ASSERT(encoder->usr, encoder->io_now == encoder->io_last_copy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
|
static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
|
||||||
{
|
{
|
||||||
spice_return_val_if_fail(io_ptr <= io_ptr_end, FALSE);
|
ASSERT(encoder->usr, io_ptr <= io_ptr_end);
|
||||||
|
|
||||||
encoder->io_bytes_count = io_ptr_end - io_ptr;
|
encoder->io_bytes_count = io_ptr_end - io_ptr;
|
||||||
|
encoder->io_start = io_ptr;
|
||||||
encoder->io_now = io_ptr;
|
encoder->io_now = io_ptr;
|
||||||
encoder->io_end = io_ptr_end;
|
encoder->io_end = io_ptr_end;
|
||||||
encoder->io_last_copy = NULL;
|
encoder->io_last_copy = NULL;
|
||||||
@ -274,20 +293,20 @@ static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t decode(Encoder *encoder)
|
static INLINE uint8_t decode(Encoder *encoder)
|
||||||
{
|
{
|
||||||
if (encoder->io_now == encoder->io_end) {
|
if (encoder->io_now == encoder->io_end) {
|
||||||
int num_io_bytes = more_io_bytes(encoder);
|
int num_io_bytes = more_io_bytes(encoder);
|
||||||
if (num_io_bytes <= 0) {
|
if (num_io_bytes <= 0) {
|
||||||
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
|
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
spice_assert(encoder->io_now);
|
ASSERT(encoder->usr, encoder->io_now);
|
||||||
}
|
}
|
||||||
spice_assert(encoder->io_now < encoder->io_end);
|
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
|
||||||
return *(encoder->io_now++);
|
return *(encoder->io_now++);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t decode_32(Encoder *encoder)
|
static INLINE uint32_t decode_32(Encoder *encoder)
|
||||||
{
|
{
|
||||||
uint32_t word = 0;
|
uint32_t word = 0;
|
||||||
word |= decode(encoder);
|
word |= decode(encoder);
|
||||||
@ -300,7 +319,7 @@ static inline uint32_t decode_32(Encoder *encoder)
|
|||||||
return word;
|
return word;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_io_to_decode_end(Encoder *encoder)
|
static INLINE int is_io_to_decode_end(Encoder *encoder)
|
||||||
{
|
{
|
||||||
if (encoder->io_now != encoder->io_end) {
|
if (encoder->io_now != encoder->io_end) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -374,23 +393,30 @@ void lz_destroy(LzContext *lz)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <spice/start-packed.h>
|
#ifdef __GNUC__
|
||||||
|
#define ATTR_PACKED __attribute__ ((__packed__))
|
||||||
|
#else
|
||||||
|
#define ATTR_PACKED
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* the palette images will be treated as one byte pixels. Their width should be transformed
|
/* the palette images will be treated as one byte pixels. Their width should be transformed
|
||||||
accordingly.
|
accordingly.
|
||||||
*/
|
*/
|
||||||
typedef struct SPICE_ATTR_PACKED one_byte_pixel_t {
|
typedef struct ATTR_PACKED one_byte_pixel_t {
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
} one_byte_pixel_t;
|
} one_byte_pixel_t;
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED rgb32_pixel_t {
|
typedef struct ATTR_PACKED rgb32_pixel_t {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
uint8_t pad;
|
uint8_t pad;
|
||||||
} rgb32_pixel_t;
|
} rgb32_pixel_t;
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED rgb24_pixel_t {
|
typedef struct ATTR_PACKED rgb24_pixel_t {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
@ -398,7 +424,11 @@ typedef struct SPICE_ATTR_PACKED rgb24_pixel_t {
|
|||||||
|
|
||||||
typedef uint16_t rgb16_pixel_t;
|
typedef uint16_t rgb16_pixel_t;
|
||||||
|
|
||||||
#include <spice/end-packed.h>
|
#ifndef __GNUC__
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef ATTR_PACKED
|
||||||
|
|
||||||
|
|
||||||
#define MAX_COPY 32
|
#define MAX_COPY 32
|
||||||
@ -446,13 +476,6 @@ typedef uint16_t rgb16_pixel_t;
|
|||||||
#define TO_RGB32
|
#define TO_RGB32
|
||||||
#include "lz_decompress_tmpl.c"
|
#include "lz_decompress_tmpl.c"
|
||||||
|
|
||||||
#define LZ_A8
|
|
||||||
#include "lz_compress_tmpl.c"
|
|
||||||
#define LZ_A8
|
|
||||||
#include "lz_decompress_tmpl.c"
|
|
||||||
#define LZ_A8
|
|
||||||
#define TO_RGB32
|
|
||||||
#include "lz_decompress_tmpl.c"
|
|
||||||
|
|
||||||
#define LZ_RGB16
|
#define LZ_RGB16
|
||||||
#include "lz_compress_tmpl.c"
|
#include "lz_compress_tmpl.c"
|
||||||
@ -481,44 +504,6 @@ typedef uint16_t rgb16_pixel_t;
|
|||||||
#undef LZ_UNEXPECT_CONDITIONAL
|
#undef LZ_UNEXPECT_CONDITIONAL
|
||||||
#undef LZ_EXPECT_CONDITIONAL
|
#undef LZ_EXPECT_CONDITIONAL
|
||||||
|
|
||||||
static void lz_set_sizes(Encoder *encoder, int type, int width, int height, int stride)
|
|
||||||
{
|
|
||||||
if (width < 0) {
|
|
||||||
encoder->usr->error(encoder->usr, "invalid lz width %d\n", width);
|
|
||||||
}
|
|
||||||
if (height < 0) {
|
|
||||||
encoder->usr->error(encoder->usr, "invalid lz height %d\n", height);
|
|
||||||
}
|
|
||||||
if (stride < 0) {
|
|
||||||
encoder->usr->error(encoder->usr, "invalid lz stride %d\n", stride);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_IMAGE_TYPE_PLT[type]) {
|
|
||||||
if (stride > (width / PLT_PIXELS_PER_BYTE[type])) {
|
|
||||||
if (((width % PLT_PIXELS_PER_BYTE[type]) == 0) || (
|
|
||||||
(stride - (width / PLT_PIXELS_PER_BYTE[type])) > 1)) {
|
|
||||||
encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (stride != width * RGB_BYTES_PER_PIXEL[type]) {
|
|
||||||
encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb) %d != %d * %d (%d)\n",
|
|
||||||
stride, width, RGB_BYTES_PER_PIXEL[type],
|
|
||||||
type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid too big images
|
|
||||||
if ((uint64_t) stride * height > SPICE_MAX_IMAGE_SIZE) {
|
|
||||||
encoder->usr->error(encoder->usr, "image too large\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder->type = type;
|
|
||||||
encoder->width = width;
|
|
||||||
encoder->height = height;
|
|
||||||
encoder->stride = stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
|
int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
|
||||||
uint8_t *lines, unsigned int num_lines, int stride,
|
uint8_t *lines, unsigned int num_lines, int stride,
|
||||||
uint8_t *io_ptr, unsigned int num_io_bytes)
|
uint8_t *io_ptr, unsigned int num_io_bytes)
|
||||||
@ -526,7 +511,23 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do
|
|||||||
Encoder *encoder = (Encoder *)lz;
|
Encoder *encoder = (Encoder *)lz;
|
||||||
uint8_t *io_ptr_end = io_ptr + num_io_bytes;
|
uint8_t *io_ptr_end = io_ptr + num_io_bytes;
|
||||||
|
|
||||||
lz_set_sizes(encoder, type, width, height, stride);
|
encoder->type = type;
|
||||||
|
encoder->width = width;
|
||||||
|
encoder->height = height;
|
||||||
|
encoder->stride = stride;
|
||||||
|
|
||||||
|
if (IS_IMAGE_TYPE_PLT[encoder->type]) {
|
||||||
|
if (encoder->stride > (width / PLT_PIXELS_PER_BYTE[encoder->type])) {
|
||||||
|
if (((width % PLT_PIXELS_PER_BYTE[encoder->type]) == 0) || (
|
||||||
|
(encoder->stride - (width / PLT_PIXELS_PER_BYTE[encoder->type])) > 1)) {
|
||||||
|
encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (encoder->stride != width * RGB_BYTES_PER_PIXEL[encoder->type]) {
|
||||||
|
encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb)\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// assign the output buffer
|
// assign the output buffer
|
||||||
if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
|
if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
|
||||||
@ -570,9 +571,6 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do
|
|||||||
case LZ_IMAGE_TYPE_XXXA:
|
case LZ_IMAGE_TYPE_XXXA:
|
||||||
lz_rgb_alpha_compress(encoder);
|
lz_rgb_alpha_compress(encoder);
|
||||||
break;
|
break;
|
||||||
case LZ_IMAGE_TYPE_A8:
|
|
||||||
lz_a8_compress(encoder);
|
|
||||||
break;
|
|
||||||
case LZ_IMAGE_TYPE_INVALID:
|
case LZ_IMAGE_TYPE_INVALID:
|
||||||
default:
|
default:
|
||||||
encoder->usr->error(encoder->usr, "bad image type\n");
|
encoder->usr->error(encoder->usr, "bad image type\n");
|
||||||
@ -612,15 +610,10 @@ void lz_decode_begin(LzContext *lz, uint8_t *io_ptr, unsigned int num_io_bytes,
|
|||||||
encoder->usr->error(encoder->usr, "bad version\n");
|
encoder->usr->error(encoder->usr, "bad version\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int type = decode_32(encoder);
|
encoder->type = (LzImageType)decode_32(encoder);
|
||||||
if (type <= LZ_IMAGE_TYPE_INVALID || type > LZ_IMAGE_TYPE_A8) {
|
encoder->width = decode_32(encoder);
|
||||||
encoder->usr->error(encoder->usr, "invalid lz type %d\n", type);
|
encoder->height = decode_32(encoder);
|
||||||
}
|
encoder->stride = decode_32(encoder);
|
||||||
int width = decode_32(encoder);
|
|
||||||
int height = decode_32(encoder);
|
|
||||||
int stride = decode_32(encoder);
|
|
||||||
lz_set_sizes(encoder, type, width, height, stride);
|
|
||||||
|
|
||||||
*out_top_down = decode_32(encoder);
|
*out_top_down = decode_32(encoder);
|
||||||
|
|
||||||
*out_width = encoder->width;
|
*out_width = encoder->width;
|
||||||
@ -653,7 +646,6 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
if (!encoder->palette) {
|
if (!encoder->palette) {
|
||||||
encoder->usr->error(encoder->usr,
|
encoder->usr->error(encoder->usr,
|
||||||
"a palette is missing (for bpp to rgb decoding)\n");
|
"a palette is missing (for bpp to rgb decoding)\n");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
switch (encoder->type) {
|
switch (encoder->type) {
|
||||||
case LZ_IMAGE_TYPE_PLT1_BE:
|
case LZ_IMAGE_TYPE_PLT1_BE:
|
||||||
@ -715,7 +707,7 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
if (encoder->type == to_type) {
|
if (encoder->type == to_type) {
|
||||||
out_size = lz_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
out_size = lz_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
||||||
alpha_size = lz_rgb_alpha_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
alpha_size = lz_rgb_alpha_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
||||||
spice_assert(alpha_size == size);
|
ASSERT(encoder->usr, alpha_size == size);
|
||||||
} else {
|
} else {
|
||||||
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
||||||
}
|
}
|
||||||
@ -728,17 +720,6 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LZ_IMAGE_TYPE_A8:
|
|
||||||
if (encoder->type == to_type) {
|
|
||||||
alpha_size = lz_a8_decompress(encoder, (one_byte_pixel_t *)buf, size);
|
|
||||||
out_size = alpha_size;
|
|
||||||
} else if (to_type == LZ_IMAGE_TYPE_RGB32) {
|
|
||||||
alpha_size = lz_a8_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
|
||||||
out_size = alpha_size;
|
|
||||||
} else {
|
|
||||||
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LZ_IMAGE_TYPE_PLT1_LE:
|
case LZ_IMAGE_TYPE_PLT1_LE:
|
||||||
case LZ_IMAGE_TYPE_PLT1_BE:
|
case LZ_IMAGE_TYPE_PLT1_BE:
|
||||||
case LZ_IMAGE_TYPE_PLT4_LE:
|
case LZ_IMAGE_TYPE_PLT4_LE:
|
||||||
@ -750,8 +731,8 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spice_assert(is_io_to_decode_end(encoder));
|
ASSERT(encoder->usr, is_io_to_decode_end(encoder));
|
||||||
spice_assert(out_size == size);
|
ASSERT(encoder->usr, out_size == size);
|
||||||
|
|
||||||
if (out_size != size) {
|
if (out_size != size) {
|
||||||
encoder->usr->error(encoder->usr, "bad decode size\n");
|
encoder->usr->error(encoder->usr, "bad decode size\n");
|
||||||
|
|||||||
24
common/lz.h
24
common/lz.h
@ -3,26 +3,24 @@
|
|||||||
dictionary compression for images based on fastlz (http://www.fastlz.org/)
|
dictionary compression for images based on fastlz (http://www.fastlz.org/)
|
||||||
(Distributed under MIT license).
|
(Distributed under MIT license).
|
||||||
*/
|
*/
|
||||||
#ifndef H_SPICE_COMMON_LZ
|
#ifndef __LZ_H
|
||||||
#define H_SPICE_COMMON_LZ
|
#define __LZ_H
|
||||||
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#include "lz_common.h"
|
#include "lz_common.h"
|
||||||
#include "lz_config.h"
|
#include "lz_config.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "macros.h"
|
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void *LzContext;
|
typedef void *LzContext;
|
||||||
|
|
||||||
typedef struct LzUsrContext LzUsrContext;
|
typedef struct LzUsrContext LzUsrContext;
|
||||||
struct LzUsrContext {
|
struct LzUsrContext {
|
||||||
SPICE_GNUC_NORETURN
|
void (*error)(LzUsrContext *usr, const char *fmt, ...);
|
||||||
SPICE_GNUC_PRINTF(2, 3) void (*error)(LzUsrContext *usr, const char *fmt, ...);
|
void (*warn)(LzUsrContext *usr, const char *fmt, ...);
|
||||||
SPICE_GNUC_PRINTF(2, 3) void (*warn)(LzUsrContext *usr, const char *fmt, ...);
|
void (*info)(LzUsrContext *usr, const char *fmt, ...);
|
||||||
SPICE_GNUC_PRINTF(2, 3) void (*info)(LzUsrContext *usr, const char *fmt, ...);
|
|
||||||
void *(*malloc)(LzUsrContext *usr, int size);
|
void *(*malloc)(LzUsrContext *usr, int size);
|
||||||
void (*free)(LzUsrContext *usr, void *ptr);
|
void (*free)(LzUsrContext *usr, void *ptr);
|
||||||
int (*more_space)(LzUsrContext *usr, uint8_t **io_ptr); // get the next chunk of the
|
int (*more_space)(LzUsrContext *usr, uint8_t **io_ptr); // get the next chunk of the
|
||||||
@ -77,6 +75,8 @@ LzContext *lz_create(LzUsrContext *usr);
|
|||||||
|
|
||||||
void lz_destroy(LzContext *lz);
|
void lz_destroy(LzContext *lz);
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_LZ
|
#endif // __LZ_H
|
||||||
|
|||||||
@ -20,13 +20,14 @@
|
|||||||
|
|
||||||
/*common header for encoder and decoder*/
|
/*common header for encoder and decoder*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_LZ_COMMON
|
#ifndef _LZ_COMMON_H
|
||||||
#define H_SPICE_COMMON_LZ_COMMON
|
#define _LZ_COMMON_H
|
||||||
|
|
||||||
#include <spice/macros.h>
|
#ifdef __cplusplus
|
||||||
#include "verify.h"
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
//#define DEBUG
|
||||||
|
|
||||||
/* change the max window size will require change in the encoding format*/
|
/* change the max window size will require change in the encoding format*/
|
||||||
#define LZ_MAX_WINDOW_SIZE (1 << 25)
|
#define LZ_MAX_WINDOW_SIZE (1 << 25)
|
||||||
@ -43,30 +44,26 @@ typedef enum {
|
|||||||
LZ_IMAGE_TYPE_RGB24,
|
LZ_IMAGE_TYPE_RGB24,
|
||||||
LZ_IMAGE_TYPE_RGB32,
|
LZ_IMAGE_TYPE_RGB32,
|
||||||
LZ_IMAGE_TYPE_RGBA,
|
LZ_IMAGE_TYPE_RGBA,
|
||||||
LZ_IMAGE_TYPE_XXXA,
|
LZ_IMAGE_TYPE_XXXA
|
||||||
LZ_IMAGE_TYPE_A8
|
|
||||||
} LzImageType;
|
} LzImageType;
|
||||||
|
|
||||||
#define LZ_IMAGE_TYPE_MASK 0x0f
|
#define LZ_IMAGE_TYPE_MASK 0x0f
|
||||||
#define LZ_IMAGE_TYPE_LOG 4 // number of bits required for coding the image type
|
#define LZ_IMAGE_TYPE_LOG 4 // number of bits required for coding the image type
|
||||||
|
|
||||||
/* access to the arrays is based on the image types */
|
/* access to the arrays is based on the image types */
|
||||||
static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0};
|
static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
|
||||||
static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1};
|
static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
|
||||||
static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1};
|
static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1};
|
||||||
static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 1};
|
static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4};
|
||||||
|
|
||||||
verify(SPICE_N_ELEMENTS(IS_IMAGE_TYPE_PLT) == (LZ_IMAGE_TYPE_A8 + 1));
|
|
||||||
verify(SPICE_N_ELEMENTS(IS_IMAGE_TYPE_RGB) == (LZ_IMAGE_TYPE_A8 + 1));
|
|
||||||
verify(SPICE_N_ELEMENTS(PLT_PIXELS_PER_BYTE) == (LZ_IMAGE_TYPE_PLT8 + 1));
|
|
||||||
verify(SPICE_N_ELEMENTS(RGB_BYTES_PER_PIXEL) == (LZ_IMAGE_TYPE_A8 + 1));
|
|
||||||
|
|
||||||
/* ASCII "LZ " */
|
#define LZ_MAGIC (*(uint32_t *)"LZ ")
|
||||||
#define LZ_MAGIC 0x20205a4c
|
|
||||||
#define LZ_VERSION_MAJOR 1U
|
#define LZ_VERSION_MAJOR 1U
|
||||||
#define LZ_VERSION_MINOR 1U
|
#define LZ_VERSION_MINOR 1U
|
||||||
#define LZ_VERSION ((LZ_VERSION_MAJOR << 16) | (LZ_VERSION_MINOR & 0xffff))
|
#define LZ_VERSION ((LZ_VERSION_MAJOR << 16) | (LZ_VERSION_MINOR & 0xffff))
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_LZ_COMMON
|
#endif // _LZ_COMMON_H
|
||||||
|
|||||||
@ -40,9 +40,11 @@
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DJB2_START 5381
|
#define DJB2_START 5381;
|
||||||
#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;}
|
#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -69,21 +71,6 @@
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LZ_A8
|
|
||||||
#define PIXEL one_byte_pixel_t
|
|
||||||
#define FNAME(name) lz_a8_##name
|
|
||||||
#define ENCODE_PIXEL(e, pix) encode(e, (pix).a) // gets the pixel and write only the needed bytes
|
|
||||||
// from the pixel
|
|
||||||
#define SAME_PIXEL(pix1, pix2) ((pix1).a == (pix2).a)
|
|
||||||
#define HASH_FUNC(v, p) { \
|
|
||||||
v = DJB2_START; \
|
|
||||||
DJB2_HASH(v, p[0].a); \
|
|
||||||
DJB2_HASH(v, p[1].a); \
|
|
||||||
DJB2_HASH(v, p[2].a); \
|
|
||||||
v &= HASH_MASK; \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LZ_RGB_ALPHA
|
#ifdef LZ_RGB_ALPHA
|
||||||
//#undef LZ_RGB_ALPHA
|
//#undef LZ_RGB_ALPHA
|
||||||
#define PIXEL rgb32_pixel_t
|
#define PIXEL rgb32_pixel_t
|
||||||
@ -103,8 +90,9 @@
|
|||||||
#ifdef LZ_RGB16
|
#ifdef LZ_RGB16
|
||||||
#define PIXEL rgb16_pixel_t
|
#define PIXEL rgb16_pixel_t
|
||||||
#define FNAME(name) lz_rgb16_##name
|
#define FNAME(name) lz_rgb16_##name
|
||||||
#define GET_rgb(pix) ((pix) & 0x7fffu)
|
#define GET_r(pix) (((pix) >> 10) & 0x1f)
|
||||||
#define SAME_PIXEL(p1, p2) (GET_rgb(p1) == GET_rgb(p2))
|
#define GET_g(pix) (((pix) >> 5) & 0x1f)
|
||||||
|
#define GET_b(pix) ((pix) & 0x1f)
|
||||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);}
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);}
|
||||||
|
|
||||||
#define HASH_FUNC(v, p) { \
|
#define HASH_FUNC(v, p) { \
|
||||||
@ -122,17 +110,20 @@
|
|||||||
#ifdef LZ_RGB24
|
#ifdef LZ_RGB24
|
||||||
#define PIXEL rgb24_pixel_t
|
#define PIXEL rgb24_pixel_t
|
||||||
#define FNAME(name) lz_rgb24_##name
|
#define FNAME(name) lz_rgb24_##name
|
||||||
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LZ_RGB32
|
#ifdef LZ_RGB32
|
||||||
#define PIXEL rgb32_pixel_t
|
#define PIXEL rgb32_pixel_t
|
||||||
#define FNAME(name) lz_rgb32_##name
|
#define FNAME(name) lz_rgb32_##name
|
||||||
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
#define GET_r(pix) ((pix).r)
|
||||||
#define SAME_PIXEL(p1, p2) ((p1).r == (p2).r && (p1).g == (p2).g && (p1).b == (p2).b)
|
#define GET_g(pix) ((pix).g)
|
||||||
|
#define GET_b(pix) ((pix).b)
|
||||||
#define HASH_FUNC(v, p) { \
|
#define HASH_FUNC(v, p) { \
|
||||||
v = DJB2_START; \
|
v = DJB2_START; \
|
||||||
DJB2_HASH(v, p[0].r); \
|
DJB2_HASH(v, p[0].r); \
|
||||||
@ -148,6 +139,12 @@
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
|
#define SAME_PIXEL(p1, p2) (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
|
||||||
|
GET_b(p1) == GET_b(p2))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PIXEL_ID(pix_ptr, seg_ptr) (pix_ptr - ((PIXEL *)seg_ptr->lines) + seg_ptr->size_delta)
|
#define PIXEL_ID(pix_ptr, seg_ptr) (pix_ptr - ((PIXEL *)seg_ptr->lines) + seg_ptr->size_delta)
|
||||||
|
|
||||||
// when encoding, the ref can be in previous segment, and we should check that it doesn't
|
// when encoding, the ref can be in previous segment, and we should check that it doesn't
|
||||||
@ -180,7 +177,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
size_t distance;
|
size_t distance;
|
||||||
|
|
||||||
/* minimum match length */
|
/* minimum match length */
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
||||||
size_t len = 3;
|
size_t len = 3;
|
||||||
#elif defined(LZ_RGB16)
|
#elif defined(LZ_RGB16)
|
||||||
size_t len = 2;
|
size_t len = 2;
|
||||||
@ -202,7 +199,9 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ip += 3;
|
ip += 3;
|
||||||
ref = anchor + 2;
|
ref = anchor + 2;
|
||||||
ref_limit = (PIXEL *)(seg->lines_end);
|
ref_limit = (PIXEL *)(seg->lines_end);
|
||||||
|
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
|
len = 3;
|
||||||
|
#endif
|
||||||
goto match;
|
goto match;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,7 +234,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ip++;
|
ip++;
|
||||||
|
|
||||||
/* minimum match length for rgb16 is 2 and for plt and alpha is 3 */
|
/* minimum match length for rgb16 is 2 and for plt and alpha is 3 */
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16) || defined(LZ_A8)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -245,7 +244,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ip++;
|
ip++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -256,7 +255,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
#endif
|
#endif
|
||||||
/* far, needs at least 5-byte match */
|
/* far, needs at least 5-byte match */
|
||||||
if (distance >= MAX_DISTANCE) {
|
if (distance >= MAX_DISTANCE) {
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
||||||
if (ref >= (ref_limit - 1)) {
|
if (ref >= (ref_limit - 1)) {
|
||||||
goto literal;
|
goto literal;
|
||||||
}
|
}
|
||||||
@ -273,7 +272,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
len++;
|
len++;
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -311,15 +310,18 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
|
|||||||
// TODO: maybe separate a run from the same seg or from different ones in order
|
// TODO: maybe separate a run from the same seg or from different ones in order
|
||||||
// to spare ref < ref_limit and that way we can also perform 8 calls of
|
// to spare ref < ref_limit and that way we can also perform 8 calls of
|
||||||
// (ref++ != ip++) outside a loop
|
// (ref++ != ip++) outside a loop
|
||||||
while ((ip < ip_bound) && (ref < ref_limit)) {
|
for (;;) {
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
while ((ip < ip_bound) && (ref < ref_limit)) {
|
||||||
ref++;
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ip++;
|
ref++;
|
||||||
break;
|
ip++;
|
||||||
} else {
|
break;
|
||||||
ref++;
|
} else {
|
||||||
ip++;
|
ref++;
|
||||||
|
ip++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,23 +393,27 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
|
|||||||
|
|
||||||
/* update the hash at match boundary */
|
/* update the hash at match boundary */
|
||||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
if (ip > anchor)
|
if (ip > anchor) {
|
||||||
#endif
|
#endif
|
||||||
{
|
HASH_FUNC(hval, ip);
|
||||||
HASH_FUNC(hval, ip);
|
encoder->htab[hval].ref = (uint8_t *)ip;
|
||||||
encoder->htab[hval].ref = (uint8_t *)ip;
|
|
||||||
encoder->htab[hval].image_seg = seg;
|
|
||||||
}
|
|
||||||
ip++;
|
ip++;
|
||||||
|
encoder->htab[hval].image_seg = seg;
|
||||||
|
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
|
} else {ip++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
if (ip > anchor)
|
if (ip > anchor) {
|
||||||
#endif
|
#endif
|
||||||
{
|
HASH_FUNC(hval, ip);
|
||||||
HASH_FUNC(hval, ip);
|
encoder->htab[hval].ref = (uint8_t *)ip;
|
||||||
encoder->htab[hval].ref = (uint8_t *)ip;
|
|
||||||
encoder->htab[hval].image_seg = seg;
|
|
||||||
}
|
|
||||||
ip++;
|
ip++;
|
||||||
|
encoder->htab[hval].image_seg = seg;
|
||||||
|
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
|
} else {ip++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/* assuming literal copy */
|
/* assuming literal copy */
|
||||||
encode_copy_count(encoder, MAX_COPY - 1);
|
encode_copy_count(encoder, MAX_COPY - 1);
|
||||||
continue;
|
continue;
|
||||||
@ -507,11 +513,17 @@ static void FNAME(compress)(Encoder *encoder)
|
|||||||
#undef PIXEL
|
#undef PIXEL
|
||||||
#undef ENCODE_PIXEL
|
#undef ENCODE_PIXEL
|
||||||
#undef SAME_PIXEL
|
#undef SAME_PIXEL
|
||||||
|
#undef LZ_READU16
|
||||||
#undef HASH_FUNC
|
#undef HASH_FUNC
|
||||||
#undef GET_rgb
|
#undef BYTES_TO_16
|
||||||
|
#undef HASH_FUNC_16
|
||||||
|
#undef GET_r
|
||||||
|
#undef GET_g
|
||||||
|
#undef GET_b
|
||||||
|
#undef GET_CODE
|
||||||
#undef LZ_PLT
|
#undef LZ_PLT
|
||||||
#undef LZ_RGB_ALPHA
|
#undef LZ_RGB_ALPHA
|
||||||
#undef LZ_RGB16
|
#undef LZ_RGB16
|
||||||
#undef LZ_RGB24
|
#undef LZ_RGB24
|
||||||
#undef LZ_RGB32
|
#undef LZ_RGB32
|
||||||
#undef LZ_A8
|
#undef HASH_FUNC2
|
||||||
|
|||||||
@ -18,8 +18,8 @@
|
|||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_LZ_CONFIG
|
#ifndef __LZ_CONFIG_H
|
||||||
#define H_SPICE_COMMON_LZ_CONFIG
|
#define __LZ_CONFIG_H
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
@ -36,4 +36,4 @@
|
|||||||
#endif // QXLDD
|
#endif // QXLDD
|
||||||
#endif //__GNUC__
|
#endif //__GNUC__
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_LZ_CONFIG
|
#endif //__LZ_CONFIG_H
|
||||||
|
|||||||
@ -50,16 +50,18 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
For each output pixel type the following macros are defined:
|
For each output pixel type the following macros are defined:
|
||||||
OUT_PIXEL - the output pixel type
|
OUT_PIXEL - the output pixel type
|
||||||
COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and increases
|
COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and increases
|
||||||
out. Used in RLE. Need special handling because in alpha we
|
out. Used in RLE. Need special handling because in alpha we
|
||||||
copy only the pad byte.
|
copy only the pad byte.
|
||||||
COPY_REF_PIXEL(ref, out) - copies the pixel pointed by ref to the pixel pointed by out.
|
COPY_REF_PIXEL(ref, out) - copies the pixel pointed by ref to the pixel pointed by out.
|
||||||
Increases ref and out.
|
Increases ref and out.
|
||||||
COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
|
COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
|
||||||
buffer. Increases out.
|
buffer. Increases out.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(LZ_RGB_ALPHA)
|
#if !defined(LZ_RGB_ALPHA)
|
||||||
#define COPY_PIXEL(p, out) (*out++ = p)
|
#define COPY_PIXEL(p, out) (*out++ = p)
|
||||||
@ -151,26 +153,6 @@
|
|||||||
#endif // TO_RGB32
|
#endif // TO_RGB32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CAST_PLT_DISTANCE
|
|
||||||
#define CAST_PLT_DISTANCE(dist) (dist)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LZ_A8
|
|
||||||
#ifndef TO_RGB32
|
|
||||||
#define OUT_PIXEL one_byte_pixel_t
|
|
||||||
#define FNAME(name) lz_a8_##name
|
|
||||||
#define COPY_COMP_PIXEL(encoder, out) {out->a = decode(encoder); out++;}
|
|
||||||
#else // TO_RGB32
|
|
||||||
#define OUT_PIXEL rgb32_pixel_t
|
|
||||||
#define FNAME(name) lz_a8_to_rgb32_##name
|
|
||||||
#define COPY_COMP_PIXEL(encoder, out) { \
|
|
||||||
(out)->b = (out)->g = (out)->r = 0; \
|
|
||||||
(out)->pad = decode(encoder); \
|
|
||||||
(out)++; \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LZ_RGB16
|
#ifdef LZ_RGB16
|
||||||
#ifndef TO_RGB32
|
#ifndef TO_RGB32
|
||||||
#define OUT_PIXEL rgb16_pixel_t
|
#define OUT_PIXEL rgb16_pixel_t
|
||||||
@ -222,18 +204,18 @@
|
|||||||
static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
||||||
{
|
{
|
||||||
OUT_PIXEL *op = out_buf;
|
OUT_PIXEL *op = out_buf;
|
||||||
OUT_PIXEL *const op_limit = out_buf + size;
|
OUT_PIXEL *op_limit = out_buf + size;
|
||||||
|
uint32_t ctrl = decode(encoder);
|
||||||
|
int loop = TRUE;
|
||||||
|
|
||||||
for (;;) {
|
do {
|
||||||
uint32_t ctrl = decode(encoder);
|
const OUT_PIXEL *ref = op;
|
||||||
|
uint32_t len = ctrl >> 5;
|
||||||
|
uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
|
||||||
|
|
||||||
if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
|
if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
|
||||||
/* retrieving the reference and the match length */
|
/* retrieving the reference and the match length */
|
||||||
|
|
||||||
const OUT_PIXEL *ref = op;
|
|
||||||
uint32_t len = ctrl >> 5;
|
|
||||||
uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
|
|
||||||
|
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
len--;
|
len--;
|
||||||
//ref -= ofs;
|
//ref -= ofs;
|
||||||
@ -255,7 +237,7 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
||||||
len += 3; // length is biased by 2 + 1 (fixing bias)
|
len += 3; // length is biased by 2 + 1 (fixing bias)
|
||||||
#elif defined(LZ_RGB16)
|
#elif defined(LZ_RGB16)
|
||||||
len += 2; // length is biased by 1 + 1 (fixing bias)
|
len += 2; // length is biased by 1 + 1 (fixing bias)
|
||||||
@ -264,13 +246,17 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
#endif
|
#endif
|
||||||
ofs += 1; // offset is biased by 1 (fixing bias)
|
ofs += 1; // offset is biased by 1 (fixing bias)
|
||||||
|
|
||||||
|
#if defined(TO_RGB32)
|
||||||
|
#if defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || defined(PLT1_LE)
|
||||||
ofs = CAST_PLT_DISTANCE(ofs);
|
ofs = CAST_PLT_DISTANCE(ofs);
|
||||||
len = CAST_PLT_DISTANCE(len);
|
len = CAST_PLT_DISTANCE(len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
ref -= ofs;
|
ref -= ofs;
|
||||||
|
|
||||||
spice_assert(op + len <= op_limit);
|
ASSERT(encoder->usr, op + len <= op_limit);
|
||||||
spice_assert(ref + len <= op_limit);
|
ASSERT(encoder->usr, ref + len <= op_limit);
|
||||||
spice_assert(ref >= out_buf);
|
ASSERT(encoder->usr, ref >= out_buf);
|
||||||
|
|
||||||
// TODO: optimize by not calling loop at least 3 times when not PLT_TO_RGB32 (len is
|
// TODO: optimize by not calling loop at least 3 times when not PLT_TO_RGB32 (len is
|
||||||
// always >=3). in PLT_TO_RGB32 len >= 3*number_of_pixels_per_byte
|
// always >=3). in PLT_TO_RGB32 len >= 3*number_of_pixels_per_byte
|
||||||
@ -281,31 +267,41 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
// because the number of pixel copied is larger
|
// because the number of pixel copied is larger
|
||||||
// then one...
|
// then one...
|
||||||
/* optimize copy for a run */
|
/* optimize copy for a run */
|
||||||
const OUT_PIXEL b = *ref;
|
OUT_PIXEL b = *ref;
|
||||||
for (; len; --len) {
|
for (; len; --len) {
|
||||||
COPY_PIXEL(b, op);
|
COPY_PIXEL(b, op);
|
||||||
spice_extra_assert(op <= op_limit);
|
ASSERT(encoder->usr, op <= op_limit);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (; len; --len) {
|
for (; len; --len) {
|
||||||
COPY_REF_PIXEL(ref, op);
|
COPY_REF_PIXEL(ref, op);
|
||||||
spice_extra_assert(op <= op_limit);
|
ASSERT(encoder->usr, op <= op_limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // copy
|
} else { // copy
|
||||||
ctrl++; // copy count is biased by 1
|
ctrl++; // copy count is biased by 1
|
||||||
spice_assert(op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
|
#if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \
|
||||||
|
defined(PLT1_LE))
|
||||||
|
ASSERT(encoder->usr, op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
|
||||||
|
#else
|
||||||
|
ASSERT(encoder->usr, op + ctrl <= op_limit);
|
||||||
|
#endif
|
||||||
|
COPY_COMP_PIXEL(encoder, op);
|
||||||
|
|
||||||
do {
|
ASSERT(encoder->usr, op <= op_limit);
|
||||||
|
|
||||||
|
for (--ctrl; ctrl; ctrl--) {
|
||||||
COPY_COMP_PIXEL(encoder, op);
|
COPY_COMP_PIXEL(encoder, op);
|
||||||
spice_extra_assert(op <= op_limit);
|
ASSERT(encoder->usr, op <= op_limit);
|
||||||
} while(--ctrl);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LZ_UNEXPECT_CONDITIONAL(op >= op_limit)) {
|
if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
|
||||||
break;
|
ctrl = decode(encoder);
|
||||||
|
} else {
|
||||||
|
loop = FALSE;
|
||||||
}
|
}
|
||||||
}
|
} while (LZ_EXPECT_CONDITIONAL(loop));
|
||||||
|
|
||||||
return (op - out_buf);
|
return (op - out_buf);
|
||||||
}
|
}
|
||||||
@ -319,7 +315,6 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
#undef LZ_RGB16
|
#undef LZ_RGB16
|
||||||
#undef LZ_RGB24
|
#undef LZ_RGB24
|
||||||
#undef LZ_RGB32
|
#undef LZ_RGB32
|
||||||
#undef LZ_A8
|
|
||||||
#undef LZ_RGB_ALPHA
|
#undef LZ_RGB_ALPHA
|
||||||
#undef TO_RGB32
|
#undef TO_RGB32
|
||||||
#undef OUT_PIXEL
|
#undef OUT_PIXEL
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_MACROS
|
|
||||||
#define H_SPICE_COMMON_MACROS
|
|
||||||
|
|
||||||
#include "verify.h"
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define SPICE_CONSTRUCTOR_FUNC(func_name) \
|
|
||||||
static void __attribute__((constructor)) func_name(void)
|
|
||||||
#define SPICE_DESTRUCTOR_FUNC(func_name) \
|
|
||||||
static void __attribute__((destructor)) func_name(void)
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define SPICE_CONSTRUCTOR_FUNC(func_name) \
|
|
||||||
static void func_name(void); \
|
|
||||||
static int func_name ## _wrapper(void) { func_name(); return 0; } \
|
|
||||||
__pragma(section(".CRT$XCU",read)) \
|
|
||||||
__declspec(allocate(".CRT$XCU")) static int (* _array ## func_name)(void) = func_name ## _wrapper; \
|
|
||||||
static void func_name(void)
|
|
||||||
#define SPICE_DESTRUCTOR_FUNC(func_name) \
|
|
||||||
static void func_name(void); \
|
|
||||||
static int func_name ## _wrapper(void) { func_name(); return 0; } \
|
|
||||||
__pragma(section(".CRT$XPU",read)) \
|
|
||||||
__declspec(allocate(".CRT$XPU")) static int (* _array ## func_name)(void) = func_name ## _wrapper; \
|
|
||||||
static void func_name(void)
|
|
||||||
#else
|
|
||||||
#error Please implement SPICE_CONSTRUCTOR_FUNC and SPICE_DESTRUCTOR_FUNC for this compiler
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SPICE_VERIFY(cond) verify_expr(cond, (void)1)
|
|
||||||
|
|
||||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
|
||||||
#define SPICE_UNREACHABLE __builtin_unreachable()
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define SPICE_UNREACHABLE __assume(0)
|
|
||||||
#else
|
|
||||||
#define SPICE_UNREACHABLE for(;;) continue
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_MACROS
|
|
||||||
@ -15,60 +15,34 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
#include "marshaller.h"
|
#include "marshaller.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <spice/start-packed.h>
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
int16_t val;
|
|
||||||
} int16_unaligned_t;
|
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
uint16_t val;
|
|
||||||
} uint16_unaligned_t;
|
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
int32_t val;
|
|
||||||
} int32_unaligned_t;
|
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
uint32_t val;
|
|
||||||
} uint32_unaligned_t;
|
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
int64_t val;
|
|
||||||
} int64_unaligned_t;
|
|
||||||
|
|
||||||
typedef struct SPICE_ATTR_PACKED {
|
|
||||||
uint64_t val;
|
|
||||||
} uint64_unaligned_t;
|
|
||||||
#include <spice/end-packed.h>
|
|
||||||
|
|
||||||
#define write_int8(ptr,v) (*(int8_t *)(ptr) = v)
|
|
||||||
#define write_uint8(ptr,v) (*(uint8_t *)(ptr) = v)
|
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
#define write_int16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
|
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
|
||||||
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
|
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
|
||||||
#define write_int32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
|
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||||
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
|
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||||
#define write_int64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
|
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
|
||||||
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
|
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
|
||||||
|
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = SPICE_BYTESWAP64((uint64_t)(v)))
|
||||||
|
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = SPICE_BYTESWAP64((uint64_t)(v)))
|
||||||
#else
|
#else
|
||||||
#define write_int16(ptr,v) (((int16_unaligned_t *)(ptr))->val = v)
|
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
|
||||||
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = v)
|
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
|
||||||
#define write_int32(ptr,v) (((int32_unaligned_t *)(ptr))->val = v)
|
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = v)
|
||||||
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = v)
|
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = v)
|
||||||
#define write_int64(ptr,v) (((int64_unaligned_t *)(ptr))->val = v)
|
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = v)
|
||||||
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = v)
|
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = v)
|
||||||
|
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = v)
|
||||||
|
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = v)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -94,6 +68,7 @@ typedef struct SpiceMarshallerData SpiceMarshallerData;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
SpiceMarshaller *marshaller;
|
SpiceMarshaller *marshaller;
|
||||||
int item_nr;
|
int item_nr;
|
||||||
|
int is_64bit;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
} MarshallerRef;
|
} MarshallerRef;
|
||||||
|
|
||||||
@ -105,26 +80,25 @@ struct SpiceMarshaller {
|
|||||||
MarshallerRef pointer_ref;
|
MarshallerRef pointer_ref;
|
||||||
|
|
||||||
int n_items;
|
int n_items;
|
||||||
int items_size; /* number of items available in items */
|
int items_size; /* number of items availible in items */
|
||||||
MarshallerItem *items;
|
MarshallerItem *items;
|
||||||
|
|
||||||
MarshallerItem static_items[N_STATIC_ITEMS];
|
MarshallerItem static_items[N_STATIC_ITEMS];
|
||||||
int num_fd;
|
|
||||||
int fd[4];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpiceMarshallerData {
|
struct SpiceMarshallerData {
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
size_t base;
|
size_t base;
|
||||||
|
SpiceMarshaller *marshallers;
|
||||||
SpiceMarshaller *last_marshaller;
|
SpiceMarshaller *last_marshaller;
|
||||||
|
|
||||||
size_t current_buffer_position;
|
size_t current_buffer_position;
|
||||||
MarshallerBuffer *current_buffer;
|
MarshallerBuffer *current_buffer;
|
||||||
MarshallerItem *current_buffer_item;
|
MarshallerItem *current_buffer_item;
|
||||||
|
MarshallerBuffer *buffers;
|
||||||
|
|
||||||
// first marshaller and buffer are statically allocated here
|
SpiceMarshaller static_marshaller;
|
||||||
SpiceMarshaller marshallers[1];
|
MarshallerBuffer static_buffer;
|
||||||
MarshallerBuffer buffers[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void spice_marshaller_init(SpiceMarshaller *m,
|
static void spice_marshaller_init(SpiceMarshaller *m,
|
||||||
@ -137,8 +111,6 @@ static void spice_marshaller_init(SpiceMarshaller *m,
|
|||||||
m->n_items = 0;
|
m->n_items = 0;
|
||||||
m->items_size = N_STATIC_ITEMS;
|
m->items_size = N_STATIC_ITEMS;
|
||||||
m->items = m->static_items;
|
m->items = m->static_items;
|
||||||
m->fd[0] = m->fd[1] = m->fd[2] = m->fd[3] = -1;
|
|
||||||
m->num_fd = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiceMarshaller *spice_marshaller_new(void)
|
SpiceMarshaller *spice_marshaller_new(void)
|
||||||
@ -148,15 +120,16 @@ SpiceMarshaller *spice_marshaller_new(void)
|
|||||||
|
|
||||||
d = spice_new(SpiceMarshallerData, 1);
|
d = spice_new(SpiceMarshallerData, 1);
|
||||||
|
|
||||||
d->last_marshaller = d->marshallers;
|
d->last_marshaller = d->marshallers = &d->static_marshaller;
|
||||||
d->total_size = 0;
|
d->total_size = 0;
|
||||||
d->base = 0;
|
d->base = 0;
|
||||||
|
d->buffers = &d->static_buffer;
|
||||||
d->buffers->next = NULL;
|
d->buffers->next = NULL;
|
||||||
d->current_buffer = d->buffers;
|
d->current_buffer = d->buffers;
|
||||||
d->current_buffer_position = 0;
|
d->current_buffer_position = 0;
|
||||||
d->current_buffer_item = NULL;
|
d->current_buffer_item = NULL;
|
||||||
|
|
||||||
m = d->marshallers;
|
m = &d->static_marshaller;
|
||||||
spice_marshaller_init(m, d);
|
spice_marshaller_init(m, d);
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
@ -187,7 +160,6 @@ void spice_marshaller_reset(SpiceMarshaller *m)
|
|||||||
{
|
{
|
||||||
SpiceMarshaller *m2, *next;
|
SpiceMarshaller *m2, *next;
|
||||||
SpiceMarshallerData *d;
|
SpiceMarshallerData *d;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Only supported for root marshaller */
|
/* Only supported for root marshaller */
|
||||||
assert(m->data->marshallers == m);
|
assert(m->data->marshallers == m);
|
||||||
@ -207,14 +179,6 @@ void spice_marshaller_reset(SpiceMarshaller *m)
|
|||||||
m->n_items = 0;
|
m->n_items = 0;
|
||||||
m->total_size = 0;
|
m->total_size = 0;
|
||||||
|
|
||||||
for (i = 0; i < m->num_fd; i++) {
|
|
||||||
if (m->fd[i] >= 0) {
|
|
||||||
close(m->fd[i]);
|
|
||||||
m->fd[i] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m->num_fd = 0;
|
|
||||||
|
|
||||||
d = m->data;
|
d = m->data;
|
||||||
d->last_marshaller = d->marshallers;
|
d->last_marshaller = d->marshallers;
|
||||||
d->total_size = 0;
|
d->total_size = 0;
|
||||||
@ -274,11 +238,6 @@ static size_t remaining_buffer_size(SpiceMarshallerData *d)
|
|||||||
return MARSHALLER_BUFFER_SIZE - d->current_buffer_position;
|
return MARSHALLER_BUFFER_SIZE - d->current_buffer_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reserve_space_free_data(uint8_t *data, SPICE_GNUC_UNUSED void *opaque)
|
|
||||||
{
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
|
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
|
||||||
{
|
{
|
||||||
MarshallerItem *item;
|
MarshallerItem *item;
|
||||||
@ -317,7 +276,7 @@ uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
|
|||||||
/* Large item, allocate by itself */
|
/* Large item, allocate by itself */
|
||||||
item->data = (uint8_t *)spice_malloc(size);
|
item->data = (uint8_t *)spice_malloc(size);
|
||||||
item->len = size;
|
item->len = size;
|
||||||
item->free_data = reserve_space_free_data;
|
item->free_data = (spice_marshaller_item_free_func)free;
|
||||||
item->opaque = NULL;
|
item->opaque = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* Use next buffer */
|
/* Use next buffer */
|
||||||
@ -351,8 +310,8 @@ void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size)
|
|||||||
item->len -= size;
|
item->len -= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add_by_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
||||||
spice_marshaller_item_free_func free_data, void *opaque)
|
spice_marshaller_item_free_func free_data, void *opaque)
|
||||||
{
|
{
|
||||||
MarshallerItem *item;
|
MarshallerItem *item;
|
||||||
SpiceMarshallerData *d;
|
SpiceMarshallerData *d;
|
||||||
@ -374,7 +333,7 @@ uint8_t *spice_marshaller_add_by_ref_full(SpiceMarshaller *m, uint8_t *data, siz
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t size)
|
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
|
|
||||||
@ -383,21 +342,18 @@ uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t si
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add_by_ref(SpiceMarshaller *m, const uint8_t *data, size_t size)
|
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
/* the cast to no-const here is safe as data is used for writing only if
|
return spice_marshaller_add_ref_full(m, data, size, NULL, NULL);
|
||||||
* free_data pointer is not NULL
|
|
||||||
*/
|
|
||||||
return spice_marshaller_add_by_ref_full(m, (uint8_t *) data, size, NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void spice_marshaller_add_chunks_by_ref(SpiceMarshaller *m, SpiceChunks *chunks)
|
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < chunks->num_chunks; i++) {
|
for (i = 0; i < chunks->num_chunks; i++) {
|
||||||
spice_marshaller_add_by_ref(m, chunks->chunk[i].data,
|
spice_marshaller_add_ref(m, chunks->chunk[i].data,
|
||||||
chunks->chunk[i].len);
|
chunks->chunk[i].len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,13 +373,13 @@ SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m)
|
|||||||
return m2;
|
return m2;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m)
|
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit)
|
||||||
{
|
{
|
||||||
SpiceMarshaller *m2;
|
SpiceMarshaller *m2;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
size = 4;
|
size = is_64bit ? 8 : 4;
|
||||||
|
|
||||||
p = spice_marshaller_reserve_space(m, size);
|
p = spice_marshaller_reserve_space(m, size);
|
||||||
memset(p, 0, size);
|
memset(p, 0, size);
|
||||||
@ -431,11 +387,12 @@ SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m)
|
|||||||
m2->pointer_ref.marshaller = m;
|
m2->pointer_ref.marshaller = m;
|
||||||
m2->pointer_ref.item_nr = m->n_items - 1;
|
m2->pointer_ref.item_nr = m->n_items - 1;
|
||||||
m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
|
m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
|
||||||
|
m2->pointer_ref.is_64bit = is_64bit;
|
||||||
|
|
||||||
return m2;
|
return m2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *lookup_ref(MarshallerRef *ref)
|
uint8_t *lookup_ref(MarshallerRef *ref)
|
||||||
{
|
{
|
||||||
MarshallerItem *item;
|
MarshallerItem *item;
|
||||||
|
|
||||||
@ -462,7 +419,7 @@ uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip_bytes,
|
|||||||
/* Only supported for root marshaller */
|
/* Only supported for root marshaller */
|
||||||
assert(m->data->marshallers == m);
|
assert(m->data->marshallers == m);
|
||||||
|
|
||||||
if (m->n_items == 1 && m->next == NULL) {
|
if (m->n_items == 1) {
|
||||||
*free_res = FALSE;
|
*free_res = FALSE;
|
||||||
if (m->items[0].len <= skip_bytes) {
|
if (m->items[0].len <= skip_bytes) {
|
||||||
*len = 0;
|
*len = 0;
|
||||||
@ -535,19 +492,18 @@ void spice_marshaller_flush(SpiceMarshaller *m)
|
|||||||
for (m2 = m; m2 != NULL; m2 = m2->next) {
|
for (m2 = m; m2 != NULL; m2 = m2->next) {
|
||||||
if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
|
if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
|
||||||
ptr_pos = lookup_ref(&m2->pointer_ref);
|
ptr_pos = lookup_ref(&m2->pointer_ref);
|
||||||
write_uint32(ptr_pos, spice_marshaller_get_offset(m2));
|
if (m2->pointer_ref.is_64bit) {
|
||||||
|
write_uint64(ptr_pos,
|
||||||
|
spice_marshaller_get_offset(m2));
|
||||||
|
} else {
|
||||||
|
write_uint32(ptr_pos,
|
||||||
|
spice_marshaller_get_offset(m2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifndef WIN32
|
||||||
// this definition is ABI compatible with WSABUF
|
|
||||||
struct iovec {
|
|
||||||
unsigned long iov_len;
|
|
||||||
void *iov_base;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
||||||
int n_vec, size_t skip_bytes)
|
int n_vec, size_t skip_bytes)
|
||||||
{
|
{
|
||||||
@ -569,7 +525,7 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
|||||||
if (v == n_vec) {
|
if (v == n_vec) {
|
||||||
return v; /* Not enough space in vec */
|
return v; /* Not enough space in vec */
|
||||||
}
|
}
|
||||||
vec[v].iov_base = (uint8_t *)item->data + skip_bytes;
|
vec[v].iov_base = (void *)item->data + skip_bytes;
|
||||||
vec[v].iov_len = item->len - skip_bytes;
|
vec[v].iov_len = item->len - skip_bytes;
|
||||||
skip_bytes = 0;
|
skip_bytes = 0;
|
||||||
v++;
|
v++;
|
||||||
@ -579,6 +535,7 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
|||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
|
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
|
||||||
{
|
{
|
||||||
@ -607,7 +564,7 @@ void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
|
|||||||
return (void *)ptr;
|
return (void *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spice_marshaller_set_uint32(SPICE_GNUC_UNUSED SpiceMarshaller *m, void *ref, uint32_t v)
|
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v)
|
||||||
{
|
{
|
||||||
write_uint32((uint8_t *)ref, v);
|
write_uint32((uint8_t *)ref, v);
|
||||||
}
|
}
|
||||||
@ -656,26 +613,3 @@ void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
|
|||||||
write_int8(ptr, v);
|
write_int8(ptr, v);
|
||||||
return (void *)ptr;
|
return (void *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spice_marshaller_add_fd(SpiceMarshaller *m, int fd)
|
|
||||||
{
|
|
||||||
spice_assert(m->num_fd < 4);
|
|
||||||
|
|
||||||
if (fd != -1) {
|
|
||||||
m->fd[m->num_fd] = dup(fd);
|
|
||||||
if (m->fd[m->num_fd] == -1) {
|
|
||||||
perror("dup");
|
|
||||||
}
|
|
||||||
m->num_fd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int spice_marshaller_get_fds(SpiceMarshaller *m, int fd[4])
|
|
||||||
{
|
|
||||||
int num_fd = m->num_fd;
|
|
||||||
|
|
||||||
memcpy(fd, m->fd, sizeof(m->fd));
|
|
||||||
m->num_fd = 0;
|
|
||||||
|
|
||||||
return num_fd;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -16,20 +16,18 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_MARSHALLER
|
#ifndef _H_MARSHALLER
|
||||||
#define H_SPICE_COMMON_MARSHALLER
|
#define _H_MARSHALLER
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <spice/macros.h>
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#else
|
|
||||||
struct iovec;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct SpiceMarshaller SpiceMarshaller;
|
typedef struct SpiceMarshaller SpiceMarshaller;
|
||||||
typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
|
typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
|
||||||
@ -39,11 +37,11 @@ void spice_marshaller_reset(SpiceMarshaller *m);
|
|||||||
void spice_marshaller_destroy(SpiceMarshaller *m);
|
void spice_marshaller_destroy(SpiceMarshaller *m);
|
||||||
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size);
|
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size);
|
||||||
void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size);
|
void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size);
|
||||||
uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t size);
|
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size);
|
||||||
uint8_t *spice_marshaller_add_by_ref(SpiceMarshaller *m, const uint8_t *data, size_t size);
|
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size);
|
||||||
uint8_t *spice_marshaller_add_by_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
||||||
spice_marshaller_item_free_func free_data, void *opaque);
|
spice_marshaller_item_free_func free_data, void *opaque);
|
||||||
void spice_marshaller_add_chunks_by_ref(SpiceMarshaller *m, SpiceChunks *chunks);
|
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks);
|
||||||
void spice_marshaller_flush(SpiceMarshaller *m);
|
void spice_marshaller_flush(SpiceMarshaller *m);
|
||||||
void spice_marshaller_set_base(SpiceMarshaller *m, size_t base);
|
void spice_marshaller_set_base(SpiceMarshaller *m, size_t base);
|
||||||
uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip,
|
uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip,
|
||||||
@ -53,9 +51,11 @@ size_t spice_marshaller_get_offset(SpiceMarshaller *m);
|
|||||||
size_t spice_marshaller_get_size(SpiceMarshaller *m);
|
size_t spice_marshaller_get_size(SpiceMarshaller *m);
|
||||||
size_t spice_marshaller_get_total_size(SpiceMarshaller *m);
|
size_t spice_marshaller_get_total_size(SpiceMarshaller *m);
|
||||||
SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m);
|
SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m);
|
||||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m);
|
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit);
|
||||||
|
#ifndef WIN32
|
||||||
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
||||||
int n_vec, size_t skip_bytes);
|
int n_vec, size_t skip_bytes);
|
||||||
|
#endif
|
||||||
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
|
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
|
||||||
void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
|
void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
|
||||||
void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
|
void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
|
||||||
@ -67,9 +67,8 @@ void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v);
|
|||||||
|
|
||||||
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v);
|
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v);
|
||||||
|
|
||||||
void spice_marshaller_add_fd(SpiceMarshaller *m, int fd);
|
#ifdef __cplusplus
|
||||||
int spice_marshaller_get_fds(SpiceMarshaller *m, int fd[4]);
|
}
|
||||||
|
#endif
|
||||||
SPICE_END_DECLS
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
54
common/mem.c
54
common/mem.c
@ -15,17 +15,20 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef MALLOC_ERROR
|
#ifndef MALLOC_ERROR
|
||||||
#define MALLOC_ERROR(...) SPICE_STMT_START { \
|
#define MALLOC_ERROR(format, ...) { \
|
||||||
spice_error(__VA_ARGS__); \
|
printf(format "\n", ## __VA_ARGS__); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} SPICE_STMT_END
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t spice_strnlen(const char *str, size_t max_len)
|
size_t spice_strnlen(const char *str, size_t max_len)
|
||||||
@ -43,15 +46,13 @@ size_t spice_strnlen(const char *str, size_t max_len)
|
|||||||
char *spice_strdup(const char *str)
|
char *spice_strdup(const char *str)
|
||||||
{
|
{
|
||||||
char *copy;
|
char *copy;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = strlen(str) + 1;
|
copy = (char *)spice_malloc(strlen(str) + 1);
|
||||||
copy = (char *)spice_malloc(len);
|
strcpy(copy, str);
|
||||||
memcpy(copy, str, len);
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +94,8 @@ void *spice_malloc(size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
MALLOC_ERROR("spice_malloc: panic: unable to allocate %lu bytes\n",
|
||||||
|
(unsigned long)n_bytes);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -109,7 +111,8 @@ void *spice_malloc0(size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
MALLOC_ERROR("spice_malloc0: panic: unable to allocate %lu bytes\n",
|
||||||
|
(unsigned long)n_bytes);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -123,7 +126,8 @@ void *spice_realloc(void *mem, size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
MALLOC_ERROR("spice_realloc: panic: unable to allocate %lu bytes\n",
|
||||||
|
(unsigned long)n_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(mem);
|
free(mem);
|
||||||
@ -136,7 +140,7 @@ void *spice_realloc(void *mem, size_t n_bytes)
|
|||||||
void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes)
|
void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes)
|
||||||
{
|
{
|
||||||
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
|
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
|
||||||
MALLOC_ERROR("overflow allocating %lu*%lu bytes",
|
MALLOC_ERROR("spice_malloc_n: overflow allocating %lu*%lu bytes",
|
||||||
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +179,7 @@ void *spice_realloc_n(void *mem, size_t n_blocks, size_t n_block_bytes)
|
|||||||
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
|
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
|
||||||
MALLOC_ERROR("spice_realloc_n: overflow allocating %lu*%lu bytes",
|
MALLOC_ERROR("spice_realloc_n: overflow allocating %lu*%lu bytes",
|
||||||
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return spice_realloc(mem, n_blocks * n_block_bytes);
|
return spice_realloc(mem, n_blocks * n_block_bytes);
|
||||||
}
|
}
|
||||||
@ -291,25 +295,3 @@ size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len)
|
|||||||
buffer->offset -= len;
|
buffer->offset -= len;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SPICE_DEBUG_ALIGNMENT
|
|
||||||
void spice_alignment_warning(const char *loc, void *p, unsigned sz)
|
|
||||||
{
|
|
||||||
static const char *last_loc = NULL;
|
|
||||||
if (loc != last_loc) {
|
|
||||||
last_loc = loc;
|
|
||||||
spice_log(G_LOG_LEVEL_WARNING, loc, __FUNCTION__,
|
|
||||||
"Misaligned access at %p, alignment %u", p, sz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void spice_alignment_debug(const char *loc, void *p, unsigned sz)
|
|
||||||
{
|
|
||||||
static const char *last_loc = NULL;
|
|
||||||
if (loc != last_loc) {
|
|
||||||
last_loc = loc;
|
|
||||||
spice_log(G_LOG_LEVEL_DEBUG, loc, __FUNCTION__,
|
|
||||||
"Expected misaligned access at %p, alignment %u", p, sz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // SPICE_DEBUG_ALIGNMENT
|
|
||||||
|
|||||||
61
common/mem.h
61
common/mem.h
@ -16,14 +16,19 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_MEM
|
#ifndef _H_MEM
|
||||||
#define H_SPICE_COMMON_MEM
|
#define _H_MEM
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef STDC_HEADERS
|
#ifdef STDC_HEADERS
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@ -113,7 +118,7 @@ size_t spice_strnlen(const char *str, size_t max_len);
|
|||||||
__p; \
|
__p; \
|
||||||
}))
|
}))
|
||||||
# define _SPICE_RENEW(struct_type, mem, n_structs, func) \
|
# define _SPICE_RENEW(struct_type, mem, n_structs, func) \
|
||||||
(struct_type *) (__extension__ ({ \
|
(struct_type *) (__extension__ ({ \
|
||||||
size_t __n = (size_t) (n_structs); \
|
size_t __n = (size_t) (n_structs); \
|
||||||
size_t __s = sizeof (struct_type); \
|
size_t __s = sizeof (struct_type); \
|
||||||
void *__p = (void *) (mem); \
|
void *__p = (void *) (mem); \
|
||||||
@ -129,6 +134,7 @@ size_t spice_strnlen(const char *str, size_t max_len);
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
/* Unoptimized version: always call the _n() function. */
|
/* Unoptimized version: always call the _n() function. */
|
||||||
|
|
||||||
#define _SPICE_NEW(struct_type, n_structs, func) \
|
#define _SPICE_NEW(struct_type, n_structs, func) \
|
||||||
((struct_type *) spice_##func##_n ((n_structs), sizeof (struct_type)))
|
((struct_type *) spice_##func##_n ((n_structs), sizeof (struct_type)))
|
||||||
#define _SPICE_RENEW(struct_type, mem, n_structs, func) \
|
#define _SPICE_RENEW(struct_type, mem, n_structs, func) \
|
||||||
@ -136,46 +142,6 @@ size_t spice_strnlen(const char *str, size_t max_len);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Cast to a type with stricter alignment constraints (to build with clang) */
|
|
||||||
|
|
||||||
/* Misaligned cast to a type with stricter alignment */
|
|
||||||
#ifndef SPICE_DEBUG_ALIGNMENT
|
|
||||||
#define SPICE_UNALIGNED_CAST(type, value) ((type)(void *)(value))
|
|
||||||
#define SPICE_ALIGNED_CAST(type, value) ((type)(void *)(value))
|
|
||||||
|
|
||||||
#else // SPICE_DEBUG_ALIGNMENT
|
|
||||||
#define SPICE_ALIGNED_CAST(type, value) \
|
|
||||||
((type)spice_alignment_check(G_STRLOC, \
|
|
||||||
(void *)(value), \
|
|
||||||
__alignof(*((type)0))))
|
|
||||||
|
|
||||||
#define SPICE_UNALIGNED_CAST(type, value) \
|
|
||||||
((type)spice_alignment_weak_check(G_STRLOC, \
|
|
||||||
(void *)(value), \
|
|
||||||
__alignof(*((type)0))))
|
|
||||||
|
|
||||||
extern void spice_alignment_warning(const char *loc, void *p, unsigned sz);
|
|
||||||
extern void spice_alignment_debug(const char *loc, void *p, unsigned sz);
|
|
||||||
|
|
||||||
static inline void *spice_alignment_check(const char *loc,
|
|
||||||
void *ptr, unsigned sz)
|
|
||||||
{
|
|
||||||
if (G_UNLIKELY(((uintptr_t) ptr & (sz-1U)) != 0))
|
|
||||||
spice_alignment_warning(loc, ptr, sz);
|
|
||||||
return ptr;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *spice_alignment_weak_check(const char *loc,
|
|
||||||
void *ptr, unsigned sz)
|
|
||||||
{
|
|
||||||
if (G_UNLIKELY(((uintptr_t) ptr & (sz-1U)) != 0))
|
|
||||||
spice_alignment_debug(loc, ptr, sz);
|
|
||||||
return ptr;
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif // SPICE_DEBUG_ALIGNMENT
|
|
||||||
|
|
||||||
#define spice_new(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc)
|
#define spice_new(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc)
|
||||||
#define spice_new0(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc0)
|
#define spice_new0(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc0)
|
||||||
#define spice_renew(struct_type, mem, n_structs) _SPICE_RENEW(struct_type, mem, n_structs, realloc)
|
#define spice_renew(struct_type, mem, n_structs) _SPICE_RENEW(struct_type, mem, n_structs, realloc)
|
||||||
@ -190,6 +156,7 @@ void spice_buffer_append(SpiceBuffer *buffer, const void *data, size_t len);
|
|||||||
size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len);
|
size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len);
|
||||||
size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len);
|
size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len);
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,194 +0,0 @@
|
|||||||
#
|
|
||||||
# libspice-common
|
|
||||||
#
|
|
||||||
spice_common_sources = [
|
|
||||||
'agent.c',
|
|
||||||
'agent.h',
|
|
||||||
'backtrace.c',
|
|
||||||
'backtrace.h',
|
|
||||||
'canvas_utils.c',
|
|
||||||
'canvas_utils.h',
|
|
||||||
'demarshallers.h',
|
|
||||||
'draw.h',
|
|
||||||
'lines.c',
|
|
||||||
'lines.h',
|
|
||||||
'log.c',
|
|
||||||
'log.h',
|
|
||||||
'lz.c',
|
|
||||||
'lz.h',
|
|
||||||
'lz_common.h',
|
|
||||||
'lz_config.h',
|
|
||||||
'macros.h',
|
|
||||||
'marshaller.c',
|
|
||||||
'marshaller.h',
|
|
||||||
'mem.c',
|
|
||||||
'mem.h',
|
|
||||||
'messages.h',
|
|
||||||
'pixman_utils.c',
|
|
||||||
'pixman_utils.h',
|
|
||||||
'quic.c',
|
|
||||||
'quic.h',
|
|
||||||
'quic_config.h',
|
|
||||||
'rect.h',
|
|
||||||
'region.c',
|
|
||||||
'region.h',
|
|
||||||
'ring.h',
|
|
||||||
'rop3.c',
|
|
||||||
'rop3.h',
|
|
||||||
'snd_codec.c',
|
|
||||||
'snd_codec.h',
|
|
||||||
'utils.c',
|
|
||||||
'utils.h',
|
|
||||||
'udev.c',
|
|
||||||
'udev.h',
|
|
||||||
'verify.h',
|
|
||||||
'recorder.h'
|
|
||||||
]
|
|
||||||
|
|
||||||
if get_option('instrumentation') == 'recorder'
|
|
||||||
spice_common_sources += [
|
|
||||||
'recorder/recorder.c',
|
|
||||||
'recorder/recorder.h',
|
|
||||||
'recorder/recorder_ring.c',
|
|
||||||
'recorder/recorder_ring.h'
|
|
||||||
]
|
|
||||||
endif
|
|
||||||
if get_option('instrumentation') == 'agent'
|
|
||||||
spice_common_sources += [
|
|
||||||
'agent_interface.c',
|
|
||||||
'agent_interface.h'
|
|
||||||
]
|
|
||||||
endif
|
|
||||||
|
|
||||||
spice_common_lib = static_library('spice-common', spice_common_sources,
|
|
||||||
install : false,
|
|
||||||
include_directories : spice_common_include,
|
|
||||||
dependencies : spice_common_deps)
|
|
||||||
|
|
||||||
spice_common_dep = declare_dependency(link_with : spice_common_lib,
|
|
||||||
include_directories : spice_common_include,
|
|
||||||
dependencies : spice_common_deps)
|
|
||||||
|
|
||||||
|
|
||||||
# client_demarshallers
|
|
||||||
if spice_common_generate_client_code or spice_common_generate_server_code
|
|
||||||
codegen_cmd = [python, spice_codegen]
|
|
||||||
codegen_args = ['--generate-demarshallers',
|
|
||||||
'--client',
|
|
||||||
'--include', 'common/messages.h',
|
|
||||||
'--generated-declaration-file', '@OUTPUT1@',
|
|
||||||
'@INPUT@', '@OUTPUT0@']
|
|
||||||
|
|
||||||
client_demarshallers = custom_target('client_demarshallers',
|
|
||||||
input : [spice_proto],
|
|
||||||
output : ['generated_client_demarshallers.c', 'generated_messages.h'],
|
|
||||||
install : false,
|
|
||||||
command : [codegen_cmd, codegen_args],
|
|
||||||
depend_files : [spice_codegen_files, 'messages.h'])
|
|
||||||
endif
|
|
||||||
|
|
||||||
#
|
|
||||||
# libspice-common-client
|
|
||||||
#
|
|
||||||
if spice_common_generate_client_code
|
|
||||||
# client_marshallers
|
|
||||||
codegen_args = ['--generate-marshallers',
|
|
||||||
'--generate-header',
|
|
||||||
'-P',
|
|
||||||
'--client',
|
|
||||||
'--include', 'common/client_marshallers.h',
|
|
||||||
'@INPUT0@', '@OUTPUT0@']
|
|
||||||
|
|
||||||
client_marshallers = custom_target('client_marshallers',
|
|
||||||
input : [spice_proto, client_demarshallers],
|
|
||||||
output : ['generated_client_marshallers.c', 'generated_client_marshallers.h'],
|
|
||||||
install : false,
|
|
||||||
command : [codegen_cmd, codegen_args],
|
|
||||||
depend_files : [spice_codegen_files, 'client_marshallers.h'])
|
|
||||||
|
|
||||||
spice_common_client_sources = [
|
|
||||||
client_demarshallers,
|
|
||||||
client_marshallers,
|
|
||||||
'client_marshallers.h',
|
|
||||||
'ssl_verify.c',
|
|
||||||
'ssl_verify.h',
|
|
||||||
]
|
|
||||||
|
|
||||||
spice_common_client_lib = static_library('spice-common-client', spice_common_client_sources,
|
|
||||||
install : false,
|
|
||||||
dependencies : [spice_common_dep, gio2_deps])
|
|
||||||
|
|
||||||
spice_common_client_dep = declare_dependency(sources : client_marshallers[1],
|
|
||||||
link_with : spice_common_client_lib,
|
|
||||||
dependencies : [spice_common_dep, gio2_deps])
|
|
||||||
endif
|
|
||||||
|
|
||||||
#
|
|
||||||
# libspice-common-server
|
|
||||||
#
|
|
||||||
if spice_common_generate_server_code
|
|
||||||
structs_args = [
|
|
||||||
'-M', 'String',
|
|
||||||
'-M', 'Rect',
|
|
||||||
'-M', 'Point',
|
|
||||||
'-M', 'DisplayBase',
|
|
||||||
'-M', 'Fill',
|
|
||||||
'-M', 'Opaque',
|
|
||||||
'-M', 'Copy',
|
|
||||||
'-M', 'Blend',
|
|
||||||
'-M', 'Blackness',
|
|
||||||
'-M', 'Whiteness',
|
|
||||||
'-M', 'Invers',
|
|
||||||
'-M', 'Rop3',
|
|
||||||
'-M', 'Stroke',
|
|
||||||
'-M', 'Text',
|
|
||||||
'-M', 'Transparent',
|
|
||||||
'-M', 'AlphaBlend',
|
|
||||||
'-M', 'Composite',
|
|
||||||
]
|
|
||||||
|
|
||||||
targets = [
|
|
||||||
{ 'name' : 'server_demarshallers',
|
|
||||||
'input' : [ spice_proto, client_demarshallers ],
|
|
||||||
'output' : ['generated_server_demarshallers.c'],
|
|
||||||
'codegen_args' : ['--generate-demarshallers',
|
|
||||||
'--server',
|
|
||||||
'--include', 'common/messages.h',
|
|
||||||
'@INPUT0@', '@OUTPUT0@'],
|
|
||||||
},
|
|
||||||
{ 'name' : 'server_marshallers',
|
|
||||||
'input' : [ spice_proto, client_demarshallers ],
|
|
||||||
'output' : ['generated_server_marshallers.c', 'generated_server_marshallers.h'],
|
|
||||||
'codegen_args' : ['--generate-marshallers',
|
|
||||||
'--generate-header',
|
|
||||||
'--server',
|
|
||||||
structs_args,
|
|
||||||
'--include', 'common/messages.h',
|
|
||||||
'@INPUT0@', '@OUTPUT0@']
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
spice_common_server_sources = []
|
|
||||||
spice_common_server_dep_sources = []
|
|
||||||
|
|
||||||
foreach t : targets
|
|
||||||
target = custom_target(t['name'],
|
|
||||||
input : t['input'],
|
|
||||||
output : t['output'],
|
|
||||||
install : false,
|
|
||||||
command : [codegen_cmd, t['codegen_args']],
|
|
||||||
depend_files : [spice_codegen_files, 'messages.h'])
|
|
||||||
spice_common_server_sources += target
|
|
||||||
if t['output'].length() > 1
|
|
||||||
spice_common_server_dep_sources += target[1]
|
|
||||||
endif
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
spice_common_server_lib = static_library('spice-common-server', spice_common_server_sources,
|
|
||||||
install : false,
|
|
||||||
dependencies : spice_common_dep)
|
|
||||||
|
|
||||||
spice_common_server_dep = declare_dependency(sources : spice_common_server_dep_sources,
|
|
||||||
link_with : spice_common_server_lib,
|
|
||||||
dependencies : spice_common_dep)
|
|
||||||
endif
|
|
||||||
@ -28,46 +28,498 @@
|
|||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_MESSAGES
|
#ifndef _H_MESSAGES
|
||||||
#define H_SPICE_COMMON_MESSAGES
|
#define _H_MESSAGES
|
||||||
|
|
||||||
#include <spice/protocol.h>
|
#include <spice/protocol.h>
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#ifdef USE_SMARTCARD
|
|
||||||
#include <libcacard.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct SpiceMsgCompressedData {
|
typedef struct SpiceMsgData {
|
||||||
|
uint32_t data_size;
|
||||||
|
uint8_t data[0];
|
||||||
|
} SpiceMsgData;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgEmpty {
|
||||||
|
} SpiceMsgEmpty;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgInputsInit {
|
||||||
|
uint32_t keyboard_modifiers;
|
||||||
|
} SpiceMsgInputsInit;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgInputsKeyModifiers {
|
||||||
|
uint32_t modifiers;
|
||||||
|
} SpiceMsgInputsKeyModifiers;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMainMultiMediaTime {
|
||||||
|
uint32_t time;
|
||||||
|
} SpiceMsgMainMultiMediaTime;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMainMigrationBegin {
|
||||||
|
uint16_t port;
|
||||||
|
uint16_t sport;
|
||||||
|
uint32_t host_size;
|
||||||
|
uint8_t *host_data;
|
||||||
|
uint16_t pub_key_type;
|
||||||
|
uint32_t pub_key_size;
|
||||||
|
uint8_t *pub_key_data;
|
||||||
|
uint32_t cert_subject_size;
|
||||||
|
uint8_t *cert_subject_data;
|
||||||
|
} SpiceMsgMainMigrationBegin;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMainMigrationSwitchHost {
|
||||||
|
uint16_t port;
|
||||||
|
uint16_t sport;
|
||||||
|
uint32_t host_size;
|
||||||
|
uint8_t *host_data;
|
||||||
|
uint32_t cert_subject_size;
|
||||||
|
uint8_t *cert_subject_data;
|
||||||
|
} SpiceMsgMainMigrationSwitchHost;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMigrate {
|
||||||
|
uint32_t flags;
|
||||||
|
} SpiceMsgMigrate;
|
||||||
|
|
||||||
|
typedef struct SpiceResourceID {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint32_t uncompressed_size;
|
uint64_t id;
|
||||||
uint32_t compressed_size;
|
} SpiceResourceID;
|
||||||
uint8_t *compressed_data;
|
|
||||||
} SpiceMsgCompressedData;
|
typedef struct SpiceResourceList {
|
||||||
|
uint16_t count;
|
||||||
|
SpiceResourceID resources[0];
|
||||||
|
} SpiceResourceList;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgSetAck {
|
||||||
|
uint32_t generation;
|
||||||
|
uint32_t window;
|
||||||
|
} SpiceMsgSetAck;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcAckSync {
|
||||||
|
uint32_t generation;
|
||||||
|
} SpiceMsgcAckSync;
|
||||||
|
|
||||||
|
typedef struct SpiceWaitForChannel {
|
||||||
|
uint8_t channel_type;
|
||||||
|
uint8_t channel_id;
|
||||||
|
uint64_t message_serial;
|
||||||
|
} SpiceWaitForChannel;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgWaitForChannels {
|
||||||
|
uint8_t wait_count;
|
||||||
|
SpiceWaitForChannel wait_list[0];
|
||||||
|
} SpiceMsgWaitForChannels;
|
||||||
|
|
||||||
|
typedef struct SpiceChannelId {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t id;
|
||||||
|
} SpiceChannelId;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMainInit {
|
||||||
|
uint32_t session_id;
|
||||||
|
uint32_t display_channels_hint;
|
||||||
|
uint32_t supported_mouse_modes;
|
||||||
|
uint32_t current_mouse_mode;
|
||||||
|
uint32_t agent_connected;
|
||||||
|
uint32_t agent_tokens;
|
||||||
|
uint32_t multi_media_time;
|
||||||
|
uint32_t ram_hint;
|
||||||
|
} SpiceMsgMainInit;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisconnect {
|
||||||
|
uint64_t time_stamp;
|
||||||
|
uint32_t reason; // SPICE_ERR_?
|
||||||
|
} SpiceMsgDisconnect;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgNotify {
|
||||||
|
uint64_t time_stamp;
|
||||||
|
uint32_t severity;
|
||||||
|
uint32_t visibilty;
|
||||||
|
uint32_t what;
|
||||||
|
uint32_t message_len;
|
||||||
|
uint8_t message[0];
|
||||||
|
} SpiceMsgNotify;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgChannels {
|
||||||
|
uint32_t num_of_channels;
|
||||||
|
SpiceChannelId channels[0];
|
||||||
|
} SpiceMsgChannels;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMainName {
|
||||||
|
uint32_t name_len;
|
||||||
|
uint8_t name[0];
|
||||||
|
} SpiceMsgMainName;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMainUuid {
|
||||||
|
uint8_t uuid[16];
|
||||||
|
} SpiceMsgMainUuid;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMainMouseMode {
|
||||||
|
uint32_t supported_modes;
|
||||||
|
uint32_t current_mode;
|
||||||
|
} SpiceMsgMainMouseMode;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgPing {
|
||||||
|
uint32_t id;
|
||||||
|
uint64_t timestamp;
|
||||||
|
void *data;
|
||||||
|
uint32_t data_len;
|
||||||
|
} SpiceMsgPing;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgMainAgentDisconnect {
|
||||||
|
uint32_t error_code; // SPICE_ERR_?
|
||||||
|
} SpiceMsgMainAgentDisconnect;
|
||||||
|
|
||||||
#define SPICE_AGENT_MAX_DATA_SIZE 2048
|
#define SPICE_AGENT_MAX_DATA_SIZE 2048
|
||||||
|
|
||||||
#ifdef USE_SMARTCARD
|
typedef struct SpiceMsgMainAgentTokens {
|
||||||
typedef struct SpiceMsgSmartcard {
|
uint32_t num_tokens;
|
||||||
VSCMsgType type;
|
} SpiceMsgMainAgentTokens, SpiceMsgcMainAgentTokens, SpiceMsgcMainAgentStart;
|
||||||
uint32_t length;
|
|
||||||
uint32_t reader_id;
|
typedef struct SpiceMsgcClientInfo {
|
||||||
|
uint64_t cache_size;
|
||||||
|
} SpiceMsgcClientInfo;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcMainMouseModeRequest {
|
||||||
|
uint32_t mode;
|
||||||
|
} SpiceMsgcMainMouseModeRequest;
|
||||||
|
|
||||||
|
typedef struct SpiceCursor {
|
||||||
|
uint32_t flags;
|
||||||
|
SpiceCursorHeader header;
|
||||||
|
uint32_t data_size;
|
||||||
|
uint8_t *data;
|
||||||
|
} SpiceCursor;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayMode {
|
||||||
|
uint32_t x_res;
|
||||||
|
uint32_t y_res;
|
||||||
|
uint32_t bits;
|
||||||
|
} SpiceMsgDisplayMode;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgSurfaceCreate {
|
||||||
|
uint32_t surface_id;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint32_t format;
|
||||||
|
uint32_t flags;
|
||||||
|
} SpiceMsgSurfaceCreate;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgSurfaceDestroy {
|
||||||
|
uint32_t surface_id;
|
||||||
|
} SpiceMsgSurfaceDestroy;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayBase {
|
||||||
|
uint32_t surface_id;
|
||||||
|
SpiceRect box;
|
||||||
|
SpiceClip clip;
|
||||||
|
} SpiceMsgDisplayBase;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawFill {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceFill data;
|
||||||
|
} SpiceMsgDisplayDrawFill;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawOpaque {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceOpaque data;
|
||||||
|
} SpiceMsgDisplayDrawOpaque;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawCopy {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceCopy data;
|
||||||
|
} SpiceMsgDisplayDrawCopy;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawTransparent {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceTransparent data;
|
||||||
|
} SpiceMsgDisplayDrawTransparent;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawAlphaBlend {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceAlphaBlend data;
|
||||||
|
} SpiceMsgDisplayDrawAlphaBlend;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayCopyBits {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpicePoint src_pos;
|
||||||
|
} SpiceMsgDisplayCopyBits;
|
||||||
|
|
||||||
|
typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawRop3 {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceRop3 data;
|
||||||
|
} SpiceMsgDisplayDrawRop3;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawBlackness {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceBlackness data;
|
||||||
|
} SpiceMsgDisplayDrawBlackness;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawWhiteness {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceWhiteness data;
|
||||||
|
} SpiceMsgDisplayDrawWhiteness;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawInvers {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceInvers data;
|
||||||
|
} SpiceMsgDisplayDrawInvers;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawStroke {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceStroke data;
|
||||||
|
} SpiceMsgDisplayDrawStroke;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayDrawText {
|
||||||
|
SpiceMsgDisplayBase base;
|
||||||
|
SpiceText data;
|
||||||
|
} SpiceMsgDisplayDrawText;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayInvalOne {
|
||||||
|
uint64_t id;
|
||||||
|
} SpiceMsgDisplayInvalOne;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayStreamCreate {
|
||||||
|
uint32_t surface_id;
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t codec_type;
|
||||||
|
uint64_t stamp;
|
||||||
|
uint32_t stream_width;
|
||||||
|
uint32_t stream_height;
|
||||||
|
uint32_t src_width;
|
||||||
|
uint32_t src_height;
|
||||||
|
SpiceRect dest;
|
||||||
|
SpiceClip clip;
|
||||||
|
} SpiceMsgDisplayStreamCreate;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayStreamData {
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t multi_media_time;
|
||||||
|
uint32_t data_size;
|
||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
} SpiceMsgSmartcard;
|
} SpiceMsgDisplayStreamData;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayStreamClip {
|
||||||
|
uint32_t id;
|
||||||
|
SpiceClip clip;
|
||||||
|
} SpiceMsgDisplayStreamClip;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgDisplayStreamDestroy {
|
||||||
|
uint32_t id;
|
||||||
|
} SpiceMsgDisplayStreamDestroy;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgCursorInit {
|
||||||
|
SpicePoint16 position;
|
||||||
|
uint16_t trail_length;
|
||||||
|
uint16_t trail_frequency;
|
||||||
|
uint8_t visible;
|
||||||
|
SpiceCursor cursor;
|
||||||
|
} SpiceMsgCursorInit;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgCursorSet {
|
||||||
|
SpicePoint16 position;
|
||||||
|
uint8_t visible;
|
||||||
|
SpiceCursor cursor;
|
||||||
|
} SpiceMsgCursorSet;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgCursorMove {
|
||||||
|
SpicePoint16 position;
|
||||||
|
} SpiceMsgCursorMove;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgCursorTrail {
|
||||||
|
uint16_t length;
|
||||||
|
uint16_t frequency;
|
||||||
|
} SpiceMsgCursorTrail;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcDisplayInit {
|
||||||
|
uint8_t pixmap_cache_id;
|
||||||
|
int64_t pixmap_cache_size; //in pixels
|
||||||
|
uint8_t glz_dictionary_id;
|
||||||
|
int32_t glz_dictionary_window_size; // in pixels
|
||||||
|
} SpiceMsgcDisplayInit;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcKeyDown {
|
||||||
|
uint32_t code;
|
||||||
|
} SpiceMsgcKeyDown;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcKeyUp {
|
||||||
|
uint32_t code;
|
||||||
|
} SpiceMsgcKeyUp;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcKeyModifiers {
|
||||||
|
uint32_t modifiers;
|
||||||
|
} SpiceMsgcKeyModifiers;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcMouseMotion {
|
||||||
|
int32_t dx;
|
||||||
|
int32_t dy;
|
||||||
|
uint32_t buttons_state;
|
||||||
|
} SpiceMsgcMouseMotion;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcMousePosition {
|
||||||
|
uint32_t x;
|
||||||
|
uint32_t y;
|
||||||
|
uint32_t buttons_state;
|
||||||
|
uint8_t display_id;
|
||||||
|
} SpiceMsgcMousePosition;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcMousePress {
|
||||||
|
int32_t button;
|
||||||
|
int32_t buttons_state;
|
||||||
|
} SpiceMsgcMousePress;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcMouseRelease {
|
||||||
|
int32_t button;
|
||||||
|
int32_t buttons_state;
|
||||||
|
} SpiceMsgcMouseRelease;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgAudioVolume {
|
||||||
|
uint8_t nchannels;
|
||||||
|
uint16_t volume[0];
|
||||||
|
} SpiceMsgAudioVolume;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgAudioMute {
|
||||||
|
uint8_t mute;
|
||||||
|
} SpiceMsgAudioMute;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgPlaybackMode {
|
||||||
|
uint32_t time;
|
||||||
|
uint32_t mode; //SPICE_AUDIO_DATA_MODE_?
|
||||||
|
uint8_t *data;
|
||||||
|
uint32_t data_size;
|
||||||
|
} SpiceMsgPlaybackMode, SpiceMsgcRecordMode;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgPlaybackStart {
|
||||||
|
uint32_t channels;
|
||||||
|
uint32_t format; //SPICE_AUDIO_FMT_?
|
||||||
|
uint32_t frequency;
|
||||||
|
uint32_t time;
|
||||||
|
} SpiceMsgPlaybackStart;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgPlaybackPacket {
|
||||||
|
uint32_t time;
|
||||||
|
uint8_t *data;
|
||||||
|
uint32_t data_size;
|
||||||
|
} SpiceMsgPlaybackPacket, SpiceMsgcRecordPacket;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgRecordStart {
|
||||||
|
uint32_t channels;
|
||||||
|
uint32_t format; //SPICE_AUDIO_FMT_?
|
||||||
|
uint32_t frequency;
|
||||||
|
} SpiceMsgRecordStart;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcRecordStartMark {
|
||||||
|
uint32_t time;
|
||||||
|
} SpiceMsgcRecordStartMark;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelInit {
|
||||||
|
uint16_t max_num_of_sockets;
|
||||||
|
uint32_t max_socket_data_size;
|
||||||
|
} SpiceMsgTunnelInit;
|
||||||
|
|
||||||
|
typedef uint8_t SpiceTunnelIPv4[4];
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelIpInfo {
|
||||||
|
uint16_t type;
|
||||||
|
union {
|
||||||
|
SpiceTunnelIPv4 ipv4;
|
||||||
|
} u;
|
||||||
|
uint8_t data[0];
|
||||||
|
} SpiceMsgTunnelIpInfo;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelServiceIpMap {
|
||||||
|
uint32_t service_id;
|
||||||
|
SpiceMsgTunnelIpInfo virtual_ip;
|
||||||
|
} SpiceMsgTunnelServiceIpMap;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelSocketOpen {
|
||||||
|
uint16_t connection_id;
|
||||||
|
uint32_t service_id;
|
||||||
|
uint32_t tokens;
|
||||||
|
} SpiceMsgTunnelSocketOpen;
|
||||||
|
|
||||||
|
/* connection id must be the first field in msgs directed to a specific connection */
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelSocketFin {
|
||||||
|
uint16_t connection_id;
|
||||||
|
} SpiceMsgTunnelSocketFin;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelSocketClose {
|
||||||
|
uint16_t connection_id;
|
||||||
|
} SpiceMsgTunnelSocketClose;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelSocketData {
|
||||||
|
uint16_t connection_id;
|
||||||
|
uint8_t data[0];
|
||||||
|
} SpiceMsgTunnelSocketData;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelSocketTokens {
|
||||||
|
uint16_t connection_id;
|
||||||
|
uint32_t num_tokens;
|
||||||
|
} SpiceMsgTunnelSocketTokens;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgTunnelSocketClosedAck {
|
||||||
|
uint16_t connection_id;
|
||||||
|
} SpiceMsgTunnelSocketClosedAck;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelAddGenericService {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t group;
|
||||||
|
uint32_t port;
|
||||||
|
uint64_t name;
|
||||||
|
uint64_t description;
|
||||||
|
union {
|
||||||
|
SpiceMsgTunnelIpInfo ip;
|
||||||
|
} u;
|
||||||
|
} SpiceMsgcTunnelAddGenericService;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelRemoveService {
|
||||||
|
uint32_t id;
|
||||||
|
} SpiceMsgcTunnelRemoveService;
|
||||||
|
|
||||||
|
/* connection id must be the first field in msgs directed to a specific connection */
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelSocketOpenAck {
|
||||||
|
uint16_t connection_id;
|
||||||
|
uint32_t tokens;
|
||||||
|
} SpiceMsgcTunnelSocketOpenAck;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelSocketOpenNack {
|
||||||
|
uint16_t connection_id;
|
||||||
|
} SpiceMsgcTunnelSocketOpenNack;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelSocketData {
|
||||||
|
uint16_t connection_id;
|
||||||
|
uint8_t data[0];
|
||||||
|
} SpiceMsgcTunnelSocketData;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelSocketFin {
|
||||||
|
uint16_t connection_id;
|
||||||
|
} SpiceMsgcTunnelSocketFin;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelSocketClosed {
|
||||||
|
uint16_t connection_id;
|
||||||
|
} SpiceMsgcTunnelSocketClosed;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelSocketClosedAck {
|
||||||
|
uint16_t connection_id;
|
||||||
|
} SpiceMsgcTunnelSocketClosedAck;
|
||||||
|
|
||||||
|
typedef struct SpiceMsgcTunnelSocketTokens {
|
||||||
|
uint16_t connection_id;
|
||||||
|
uint32_t num_tokens;
|
||||||
|
} SpiceMsgcTunnelSocketTokens;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <common/generated_messages.h>
|
#endif /* _H_SPICE_PROTOCOL */
|
||||||
|
|
||||||
typedef SpiceMsgMainAgentTokens SpiceMsgcMainAgentTokens;
|
|
||||||
typedef SpiceMsgMainAgentTokens SpiceMsgcMainAgentStart;
|
|
||||||
typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
|
|
||||||
typedef SpiceMsgPlaybackMode SpiceMsgcRecordMode;
|
|
||||||
typedef SpiceMsgPlaybackPacket SpiceMsgcRecordPacket;
|
|
||||||
|
|
||||||
SPICE_END_DECLS
|
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_MESSAGES
|
|
||||||
|
|||||||
44
common/mutex.h
Normal file
44
common/mutex.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _H_MUTEX
|
||||||
|
#define _H_MUTEX
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
typedef CRITICAL_SECTION mutex_t;
|
||||||
|
#define MUTEX_INIT(mutex) InitializeCriticalSection(&mutex)
|
||||||
|
#define MUTEX_LOCK(mutex) EnterCriticalSection(&mutex)
|
||||||
|
#define MUTEX_UNLOCK(mutex) LeaveCriticalSection(&mutex)
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
typedef pthread_mutex_t mutex_t;
|
||||||
|
#define MUTEX_INIT(mutex) pthread_mutex_init(&mutex, NULL);
|
||||||
|
#define MUTEX_LOCK(mutex) pthread_mutex_lock(&mutex)
|
||||||
|
#define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _H_MUTEX
|
||||||
251
common/ogl_ctx.c
Normal file
251
common/ogl_ctx.c
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
|
||||||
|
#include "ogl_ctx.h"
|
||||||
|
#include "spice_common.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OGLCTX_TYPE_PBUF,
|
||||||
|
OGLCTX_TYPE_PIXMAP,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OGLCtx {
|
||||||
|
int type;
|
||||||
|
Display *x_display;
|
||||||
|
GLXContext glx_context;
|
||||||
|
GLXDrawable drawable;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct OGLPixmapCtx {
|
||||||
|
OGLCtx base;
|
||||||
|
Pixmap pixmap;
|
||||||
|
} OGLPixmapCtx;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *oglctx_type_str(OGLCtx *ctx)
|
||||||
|
{
|
||||||
|
static const char *pbuf_str = "pbuf";
|
||||||
|
static const char *pixmap_str = "pixmap";
|
||||||
|
static const char *invalid_str = "invalid";
|
||||||
|
|
||||||
|
switch (ctx->type) {
|
||||||
|
case OGLCTX_TYPE_PBUF:
|
||||||
|
return pbuf_str;
|
||||||
|
case OGLCTX_TYPE_PIXMAP:
|
||||||
|
return pixmap_str;
|
||||||
|
default:
|
||||||
|
return invalid_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oglctx_make_current(OGLCtx *ctx)
|
||||||
|
{
|
||||||
|
if (!glXMakeCurrent(ctx->x_display, ctx->drawable, ctx->glx_context)) {
|
||||||
|
printf("%s: failed\n", __FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OGLCtx *pbuf_create(int width, int heigth)
|
||||||
|
{
|
||||||
|
OGLCtx *ctx;
|
||||||
|
Display *x_display;
|
||||||
|
int num_configs;
|
||||||
|
GLXFBConfig *fb_config;
|
||||||
|
GLXPbuffer glx_pbuf;
|
||||||
|
GLXContext glx_context;
|
||||||
|
|
||||||
|
const int glx_attributes[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||||
|
GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
|
||||||
|
GLX_RED_SIZE, 8,
|
||||||
|
GLX_GREEN_SIZE, 8,
|
||||||
|
GLX_BLUE_SIZE, 8,
|
||||||
|
GLX_ALPHA_SIZE, 8,
|
||||||
|
GLX_STENCIL_SIZE, 4,
|
||||||
|
0 };
|
||||||
|
|
||||||
|
int pbuf_attrib[] = { GLX_PRESERVED_CONTENTS, True,
|
||||||
|
GLX_PBUFFER_WIDTH, width,
|
||||||
|
GLX_PBUFFER_HEIGHT, heigth,
|
||||||
|
GLX_LARGEST_PBUFFER, False,
|
||||||
|
0, 0 };
|
||||||
|
|
||||||
|
if (!(ctx = calloc(1, sizeof(*ctx)))) {
|
||||||
|
printf("%s: alloc pbuf failed\n", __FUNCTION__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(x_display = XOpenDisplay(NULL))) {
|
||||||
|
printf("%s: open display failed\n", __FUNCTION__);
|
||||||
|
goto error_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fb_config = glXChooseFBConfig(x_display, 0, glx_attributes, &num_configs)) ||
|
||||||
|
!num_configs) {
|
||||||
|
printf("%s: choose fb config failed\n", __FUNCTION__);
|
||||||
|
goto error_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(glx_pbuf = glXCreatePbuffer(x_display, fb_config[0], pbuf_attrib))) {
|
||||||
|
goto error_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(glx_context = glXCreateNewContext(x_display, fb_config[0], GLX_RGBA_TYPE, NULL, True))) {
|
||||||
|
printf("%s: create context failed\n", __FUNCTION__);
|
||||||
|
goto error_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(fb_config);
|
||||||
|
|
||||||
|
ctx->type = OGLCTX_TYPE_PBUF;
|
||||||
|
ctx->drawable = glx_pbuf;
|
||||||
|
ctx->glx_context = glx_context;
|
||||||
|
ctx->x_display = x_display;
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
|
||||||
|
error_4:
|
||||||
|
glXDestroyPbuffer(x_display, glx_pbuf);
|
||||||
|
|
||||||
|
error_3:
|
||||||
|
XFree(fb_config);
|
||||||
|
|
||||||
|
error_2:
|
||||||
|
XCloseDisplay(x_display);
|
||||||
|
|
||||||
|
error_1:
|
||||||
|
free(ctx);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
OGLCtx *pixmap_create(int width, int heigth)
|
||||||
|
{
|
||||||
|
Display *x_display;
|
||||||
|
int num_configs;
|
||||||
|
GLXFBConfig *fb_config;
|
||||||
|
GLXPixmap glx_pixmap;
|
||||||
|
GLXContext glx_context;
|
||||||
|
Pixmap pixmap;
|
||||||
|
int screen;
|
||||||
|
Window root_window;
|
||||||
|
OGLPixmapCtx *pix;
|
||||||
|
|
||||||
|
const int glx_attributes[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||||
|
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
|
||||||
|
GLX_RED_SIZE, 8,
|
||||||
|
GLX_GREEN_SIZE, 8,
|
||||||
|
GLX_BLUE_SIZE, 8,
|
||||||
|
GLX_ALPHA_SIZE, 8,
|
||||||
|
GLX_STENCIL_SIZE, 4,
|
||||||
|
0 };
|
||||||
|
|
||||||
|
if (!(pix = calloc(1, sizeof(*pix)))) {
|
||||||
|
printf("%s: alloc pix failed\n", __FUNCTION__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(x_display = XOpenDisplay(NULL))) {
|
||||||
|
printf("%s: open display failed\n", __FUNCTION__);
|
||||||
|
goto error_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
screen = DefaultScreen(x_display);
|
||||||
|
root_window = RootWindow(x_display, screen);
|
||||||
|
|
||||||
|
if (!(fb_config = glXChooseFBConfig(x_display, 0, glx_attributes, &num_configs)) ||
|
||||||
|
!num_configs) {
|
||||||
|
printf("%s: choose fb config failed\n", __FUNCTION__);
|
||||||
|
goto error_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pixmap = XCreatePixmap(x_display, root_window, width, heigth, 32 /*use fb config*/))) {
|
||||||
|
printf("%s: create x pixmap failed\n", __FUNCTION__);
|
||||||
|
goto error_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(glx_pixmap = glXCreatePixmap(x_display, fb_config[0], pixmap, NULL))) {
|
||||||
|
printf("%s: create glx pixmap failed\n", __FUNCTION__);
|
||||||
|
goto error_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!(glx_context = glXCreateNewContext(x_display, fb_config[0], GLX_RGBA_TYPE, NULL, True))) {
|
||||||
|
printf("%s: create context failed\n", __FUNCTION__);
|
||||||
|
goto error_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(fb_config);
|
||||||
|
|
||||||
|
pix->base.type = OGLCTX_TYPE_PIXMAP;
|
||||||
|
pix->base.x_display = x_display;
|
||||||
|
pix->base.drawable = glx_pixmap;
|
||||||
|
pix->base.glx_context = glx_context;
|
||||||
|
pix->pixmap = pixmap;
|
||||||
|
|
||||||
|
return &pix->base;
|
||||||
|
|
||||||
|
error_5:
|
||||||
|
glXDestroyPixmap(x_display, glx_pixmap);
|
||||||
|
|
||||||
|
error_4:
|
||||||
|
XFreePixmap(x_display, pixmap);
|
||||||
|
|
||||||
|
error_3:
|
||||||
|
XFree(fb_config);
|
||||||
|
|
||||||
|
error_2:
|
||||||
|
XCloseDisplay(x_display);
|
||||||
|
|
||||||
|
error_1:
|
||||||
|
free(pix);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oglctx_destroy(OGLCtx *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// test is current ?
|
||||||
|
|
||||||
|
glXDestroyContext(ctx->x_display, ctx->glx_context);
|
||||||
|
switch (ctx->type) {
|
||||||
|
case OGLCTX_TYPE_PBUF:
|
||||||
|
glXDestroyPbuffer(ctx->x_display, ctx->drawable);
|
||||||
|
break;
|
||||||
|
case OGLCTX_TYPE_PIXMAP:
|
||||||
|
glXDestroyPixmap(ctx->x_display, ctx->drawable);
|
||||||
|
XFreePixmap(ctx->x_display, ((OGLPixmapCtx *)ctx)->pixmap);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PANIC("invalid ogl ctx type");
|
||||||
|
}
|
||||||
|
|
||||||
|
XCloseDisplay(ctx->x_display);
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2010 Red Hat, Inc.
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
@ -16,19 +16,23 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_CLIENT_MARSHALLERS
|
#ifndef _H_GLCTX
|
||||||
#define H_SPICE_COMMON_CLIENT_MARSHALLERS
|
#define _H_GLCTX
|
||||||
|
|
||||||
#include <spice/protocol.h>
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "messages.h"
|
typedef struct OGLCtx OGLCtx;
|
||||||
#include "common/generated_client_marshallers.h"
|
|
||||||
#include "marshaller.h"
|
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
const char *oglctx_type_str(OGLCtx *ctx);
|
||||||
|
void oglctx_make_current(OGLCtx *ctx);
|
||||||
|
OGLCtx *pbuf_create(int width, int heigth);
|
||||||
|
OGLCtx *pixmap_create(int width, int heigth);
|
||||||
|
void oglctx_destroy(OGLCtx *ctx);
|
||||||
|
|
||||||
SpiceMessageMarshallers *spice_message_marshallers_get(void);
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
SPICE_END_DECLS
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -15,26 +15,22 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
|
#include "spice_common.h"
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* src is used for most OPs, hidden within _equation attribute. For some
|
|
||||||
* operations (such as "clear" and "noop") src is not used and then we have
|
|
||||||
* to add SPICE_GNUC_UNUSED, that's just a __attribute__((__unused__)), to
|
|
||||||
* make GCC happy.
|
|
||||||
* Also, according to GCC documentation [0], the unused attribute "(...) means
|
|
||||||
* that the variable is meant to be possibly unused. GCC does not produce a
|
|
||||||
* warning for this variable.". So, we are safe adding it, even if src is used
|
|
||||||
* for most OPs.
|
|
||||||
*/
|
|
||||||
#define SOLID_RASTER_OP(_name, _size, _type, _equation) \
|
#define SOLID_RASTER_OP(_name, _size, _type, _equation) \
|
||||||
static void \
|
static void \
|
||||||
solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, SPICE_GNUC_UNUSED _type src) \
|
solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, _type src) \
|
||||||
{ \
|
{ \
|
||||||
while (len--) { \
|
while (len--) { \
|
||||||
_type dst = *ptr; \
|
_type dst = *ptr; \
|
||||||
@ -210,12 +206,12 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
|
|||||||
depth = spice_pixman_image_get_bpp(dest);
|
depth = spice_pixman_image_get_bpp(dest);
|
||||||
/* stride is in bytes, depth in bits */
|
/* stride is in bytes, depth in bits */
|
||||||
|
|
||||||
spice_assert(x >= 0);
|
ASSERT(x >= 0);
|
||||||
spice_assert(y >= 0);
|
ASSERT(y >= 0);
|
||||||
spice_assert(width > 0);
|
ASSERT(width > 0);
|
||||||
spice_assert(height > 0);
|
ASSERT(height > 0);
|
||||||
spice_assert(x + width <= pixman_image_get_width(dest));
|
ASSERT(x + width <= pixman_image_get_width(dest));
|
||||||
spice_assert(y + height <= pixman_image_get_height(dest));
|
ASSERT(y + height <= pixman_image_get_height(dest));
|
||||||
|
|
||||||
if (pixman_fill(bits,
|
if (pixman_fill(bits,
|
||||||
stride / 4,
|
stride / 4,
|
||||||
@ -235,7 +231,7 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
|
|||||||
byte_width = 2 * width;
|
byte_width = 2 * width;
|
||||||
value = (value & 0xffff) * 0x00010001;
|
value = (value & 0xffff) * 0x00010001;
|
||||||
} else {
|
} else {
|
||||||
spice_assert (depth == 32);
|
ASSERT (depth == 32)
|
||||||
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
||||||
byte_width = 4 * width;
|
byte_width = 4 * width;
|
||||||
}
|
}
|
||||||
@ -302,13 +298,13 @@ void spice_pixman_fill_rect_rop(pixman_image_t *dest,
|
|||||||
depth = spice_pixman_image_get_bpp(dest);
|
depth = spice_pixman_image_get_bpp(dest);
|
||||||
/* stride is in bytes, depth in bits */
|
/* stride is in bytes, depth in bits */
|
||||||
|
|
||||||
spice_assert(x >= 0);
|
ASSERT(x >= 0);
|
||||||
spice_assert(y >= 0);
|
ASSERT(y >= 0);
|
||||||
spice_assert(width > 0);
|
ASSERT(width > 0);
|
||||||
spice_assert(height > 0);
|
ASSERT(height > 0);
|
||||||
spice_assert(x + width <= pixman_image_get_width(dest));
|
ASSERT(x + width <= pixman_image_get_width(dest));
|
||||||
spice_assert(y + height <= pixman_image_get_height(dest));
|
ASSERT(y + height <= pixman_image_get_height(dest));
|
||||||
spice_assert(rop < 16);
|
ASSERT(rop >= 0 && rop < 16);
|
||||||
|
|
||||||
if (depth == 8) {
|
if (depth == 8) {
|
||||||
solid_rop_8_func_t rop_func = solid_rops_8[rop];
|
solid_rop_8_func_t rop_func = solid_rops_8[rop];
|
||||||
@ -362,13 +358,13 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
|
|||||||
tile_width = pixman_image_get_width(tile);
|
tile_width = pixman_image_get_width(tile);
|
||||||
tile_height = pixman_image_get_height(tile);
|
tile_height = pixman_image_get_height(tile);
|
||||||
|
|
||||||
spice_assert(x >= 0);
|
ASSERT(x >= 0);
|
||||||
spice_assert(y >= 0);
|
ASSERT(y >= 0);
|
||||||
spice_assert(width > 0);
|
ASSERT(width > 0);
|
||||||
spice_assert(height > 0);
|
ASSERT(height > 0);
|
||||||
spice_assert(x + width <= pixman_image_get_width(dest));
|
ASSERT(x + width <= pixman_image_get_width(dest));
|
||||||
spice_assert(y + height <= pixman_image_get_height(dest));
|
ASSERT(y + height <= pixman_image_get_height(dest));
|
||||||
spice_assert(depth == spice_pixman_image_get_bpp(tile));
|
ASSERT(depth == spice_pixman_image_get_bpp(tile));
|
||||||
|
|
||||||
tile_start_x = (x - offset_x) % tile_width;
|
tile_start_x = (x - offset_x) % tile_width;
|
||||||
if (tile_start_x < 0) {
|
if (tile_start_x < 0) {
|
||||||
@ -410,7 +406,7 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
spice_assert (depth == 32);
|
ASSERT (depth == 32);
|
||||||
|
|
||||||
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
||||||
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
|
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
|
||||||
@ -453,14 +449,14 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
|
|||||||
tile_width = pixman_image_get_width(tile);
|
tile_width = pixman_image_get_width(tile);
|
||||||
tile_height = pixman_image_get_height(tile);
|
tile_height = pixman_image_get_height(tile);
|
||||||
|
|
||||||
spice_assert(x >= 0);
|
ASSERT(x >= 0);
|
||||||
spice_assert(y >= 0);
|
ASSERT(y >= 0);
|
||||||
spice_assert(width > 0);
|
ASSERT(width > 0);
|
||||||
spice_assert(height > 0);
|
ASSERT(height > 0);
|
||||||
spice_assert(x + width <= pixman_image_get_width(dest));
|
ASSERT(x + width <= pixman_image_get_width(dest));
|
||||||
spice_assert(y + height <= pixman_image_get_height(dest));
|
ASSERT(y + height <= pixman_image_get_height(dest));
|
||||||
spice_assert(rop < 16);
|
ASSERT(rop >= 0 && rop < 16);
|
||||||
spice_assert(depth == spice_pixman_image_get_bpp(tile));
|
ASSERT(depth == spice_pixman_image_get_bpp(tile));
|
||||||
|
|
||||||
tile_start_x = (x - offset_x) % tile_width;
|
tile_start_x = (x - offset_x) % tile_width;
|
||||||
if (tile_start_x < 0) {
|
if (tile_start_x < 0) {
|
||||||
@ -508,7 +504,7 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
|
|||||||
} else {
|
} else {
|
||||||
tiled_rop_32_func_t rop_func = tiled_rops_32[rop];
|
tiled_rop_32_func_t rop_func = tiled_rops_32[rop];
|
||||||
|
|
||||||
spice_assert (depth == 32);
|
ASSERT (depth == 32);
|
||||||
|
|
||||||
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
||||||
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
|
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
|
||||||
@ -540,11 +536,6 @@ void spice_pixman_blit(pixman_image_t *dest,
|
|||||||
uint8_t *src_line;
|
uint8_t *src_line;
|
||||||
int byte_width;
|
int byte_width;
|
||||||
|
|
||||||
if (!src) {
|
|
||||||
fprintf(stderr, "missing src!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bits = pixman_image_get_data(dest);
|
bits = pixman_image_get_data(dest);
|
||||||
stride = pixman_image_get_stride(dest);
|
stride = pixman_image_get_stride(dest);
|
||||||
depth = spice_pixman_image_get_bpp(dest);
|
depth = spice_pixman_image_get_bpp(dest);
|
||||||
@ -578,17 +569,17 @@ void spice_pixman_blit(pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spice_assert(src_x >= 0);
|
ASSERT(src_x >= 0);
|
||||||
spice_assert(src_y >= 0);
|
ASSERT(src_y >= 0);
|
||||||
spice_assert(dest_x >= 0);
|
ASSERT(dest_x >= 0);
|
||||||
spice_assert(dest_y >= 0);
|
ASSERT(dest_y >= 0);
|
||||||
spice_assert(width > 0);
|
ASSERT(width > 0);
|
||||||
spice_assert(height > 0);
|
ASSERT(height > 0);
|
||||||
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
||||||
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
||||||
spice_assert(src_x + width <= pixman_image_get_width(src));
|
ASSERT(src_x + width <= pixman_image_get_width(src));
|
||||||
spice_assert(src_y + height <= pixman_image_get_height(src));
|
ASSERT(src_y + height <= pixman_image_get_height(src));
|
||||||
spice_assert(depth == src_depth);
|
ASSERT(depth == src_depth);
|
||||||
|
|
||||||
if (pixman_blt(src_bits,
|
if (pixman_blt(src_bits,
|
||||||
bits,
|
bits,
|
||||||
@ -610,7 +601,7 @@ void spice_pixman_blit(pixman_image_t *dest,
|
|||||||
byte_width = width * 2;
|
byte_width = width * 2;
|
||||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2;
|
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2;
|
||||||
} else {
|
} else {
|
||||||
spice_assert (depth == 32);
|
ASSERT (depth == 32);
|
||||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
||||||
byte_width = width * 4;
|
byte_width = width * 4;
|
||||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
||||||
@ -669,17 +660,17 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spice_assert(src_x >= 0);
|
ASSERT(src_x >= 0);
|
||||||
spice_assert(src_y >= 0);
|
ASSERT(src_y >= 0);
|
||||||
spice_assert(dest_x >= 0);
|
ASSERT(dest_x >= 0);
|
||||||
spice_assert(dest_y >= 0);
|
ASSERT(dest_y >= 0);
|
||||||
spice_assert(width > 0);
|
ASSERT(width > 0);
|
||||||
spice_assert(height > 0);
|
ASSERT(height > 0);
|
||||||
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
||||||
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
||||||
spice_assert(src_x + width <= pixman_image_get_width(src));
|
ASSERT(src_x + width <= pixman_image_get_width(src));
|
||||||
spice_assert(src_y + height <= pixman_image_get_height(src));
|
ASSERT(src_y + height <= pixman_image_get_height(src));
|
||||||
spice_assert(depth == src_depth);
|
ASSERT(depth == src_depth);
|
||||||
|
|
||||||
if (depth == 8) {
|
if (depth == 8) {
|
||||||
copy_rop_8_func_t rop_func = copy_rops_8[rop];
|
copy_rop_8_func_t rop_func = copy_rops_8[rop];
|
||||||
@ -706,7 +697,7 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
|
|||||||
} else {
|
} else {
|
||||||
copy_rop_32_func_t rop_func = copy_rops_32[rop];
|
copy_rop_32_func_t rop_func = copy_rops_32[rop];
|
||||||
|
|
||||||
spice_assert (depth == 32);
|
ASSERT (depth == 32);
|
||||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
||||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
||||||
|
|
||||||
@ -765,17 +756,17 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spice_assert(src_x >= 0);
|
ASSERT(src_x >= 0);
|
||||||
spice_assert(src_y >= 0);
|
ASSERT(src_y >= 0);
|
||||||
spice_assert(dest_x >= 0);
|
ASSERT(dest_x >= 0);
|
||||||
spice_assert(dest_y >= 0);
|
ASSERT(dest_y >= 0);
|
||||||
spice_assert(width > 0);
|
ASSERT(width > 0);
|
||||||
spice_assert(height > 0);
|
ASSERT(height > 0);
|
||||||
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
||||||
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
||||||
spice_assert(src_x + width <= pixman_image_get_width(src));
|
ASSERT(src_x + width <= pixman_image_get_width(src));
|
||||||
spice_assert(src_y + height <= pixman_image_get_height(src));
|
ASSERT(src_y + height <= pixman_image_get_height(src));
|
||||||
spice_assert(depth == spice_pixman_image_get_bpp(src));
|
ASSERT(depth == spice_pixman_image_get_bpp(src));
|
||||||
|
|
||||||
if (depth == 8) {
|
if (depth == 8) {
|
||||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x;
|
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x;
|
||||||
@ -815,7 +806,7 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
|
|||||||
src_line += src_stride;
|
src_line += src_stride;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
spice_assert (depth == 32);
|
ASSERT (depth == 32);
|
||||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
||||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
||||||
|
|
||||||
@ -933,7 +924,8 @@ pixman_format_code_t spice_surface_format_to_pixman(uint32_t surface_format)
|
|||||||
case SPICE_SURFACE_FMT_32_ARGB:
|
case SPICE_SURFACE_FMT_32_ARGB:
|
||||||
return PIXMAN_a8r8g8b8;
|
return PIXMAN_a8r8g8b8;
|
||||||
default:
|
default:
|
||||||
g_error("Unknown surface format %d\n", surface_format);
|
printf("Unknown surface format %d\n", surface_format);
|
||||||
|
abort();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (pixman_format_code_t)0; /* Not reached */
|
return (pixman_format_code_t)0; /* Not reached */
|
||||||
@ -966,12 +958,10 @@ pixman_format_code_t spice_bitmap_format_to_pixman(int bitmap_format,
|
|||||||
case SPICE_BITMAP_FMT_RGBA:
|
case SPICE_BITMAP_FMT_RGBA:
|
||||||
return PIXMAN_a8r8g8b8;
|
return PIXMAN_a8r8g8b8;
|
||||||
|
|
||||||
case SPICE_BITMAP_FMT_8BIT_A:
|
|
||||||
return PIXMAN_a8;
|
|
||||||
|
|
||||||
case SPICE_BITMAP_FMT_INVALID:
|
case SPICE_BITMAP_FMT_INVALID:
|
||||||
default:
|
default:
|
||||||
g_error("Unknown bitmap format %d\n", bitmap_format);
|
printf("Unknown bitmap format %d\n", bitmap_format);
|
||||||
|
abort();
|
||||||
return PIXMAN_a8r8g8b8;
|
return PIXMAN_a8r8g8b8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -995,13 +985,25 @@ pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
|
|||||||
|
|
||||||
switch (src_format) {
|
switch (src_format) {
|
||||||
case SPICE_BITMAP_FMT_32BIT:
|
case SPICE_BITMAP_FMT_32BIT:
|
||||||
pixman_format = PIXMAN_LE_x8r8g8b8;
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
pixman_format = PIXMAN_b8g8r8x8;
|
||||||
|
#else
|
||||||
|
pixman_format = PIXMAN_x8r8g8b8;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_RGBA:
|
case SPICE_BITMAP_FMT_RGBA:
|
||||||
pixman_format = PIXMAN_LE_a8r8g8b8;
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
pixman_format = PIXMAN_b8g8r8a8;
|
||||||
|
#else
|
||||||
|
pixman_format = PIXMAN_a8r8g8b8;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_24BIT:
|
case SPICE_BITMAP_FMT_24BIT:
|
||||||
pixman_format = PIXMAN_LE_r8g8b8;
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
pixman_format = PIXMAN_b8g8r8;
|
||||||
|
#else
|
||||||
|
pixman_format = PIXMAN_r8g8b8;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_16BIT:
|
case SPICE_BITMAP_FMT_16BIT:
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
@ -1035,6 +1037,26 @@ pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
|
|||||||
#define UINT32_FROM_LE(x) (x)
|
#define UINT32_FROM_LE(x) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static INLINE uint32_t rgb_16_555_to_32(uint16_t color)
|
||||||
|
{
|
||||||
|
uint32_t ret;
|
||||||
|
|
||||||
|
ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
|
||||||
|
ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
|
||||||
|
ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE uint16_t rgb_32_to_16_555(uint32_t color)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(((color) >> 3) & 0x001f) |
|
||||||
|
(((color) >> 6) & 0x03e0) |
|
||||||
|
(((color) >> 9) & 0x7c00);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
|
static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
|
||||||
uint8_t* src, int src_stride,
|
uint8_t* src, int src_stride,
|
||||||
int width, uint8_t* end)
|
int width, uint8_t* end)
|
||||||
@ -1056,15 +1078,6 @@ static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bitmap_8_to_8(uint8_t* dest, int dest_stride,
|
|
||||||
uint8_t* src, int src_stride,
|
|
||||||
int width, uint8_t* end)
|
|
||||||
{
|
|
||||||
for (; src != end; src += src_stride, dest += dest_stride) {
|
|
||||||
memcpy(dest, src, width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bitmap_24_to_32(uint8_t* dest, int dest_stride,
|
static void bitmap_24_to_32(uint8_t* dest, int dest_stride,
|
||||||
uint8_t* src, int src_stride,
|
uint8_t* src, int src_stride,
|
||||||
int width, uint8_t* end)
|
int width, uint8_t* end)
|
||||||
@ -1118,7 +1131,7 @@ static void bitmap_8_32_to_32(uint8_t *dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
spice_error("No palette");
|
PANIC("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1164,7 +1177,7 @@ static void bitmap_8_16_to_16_555(uint8_t *dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
spice_error("No palette");
|
PANIC("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1210,7 +1223,7 @@ static void bitmap_4be_32_to_32(uint8_t* dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
spice_error("No palette");
|
PANIC("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1260,7 +1273,7 @@ static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
spice_error("No palette");
|
PANIC("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1297,7 +1310,7 @@ static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int test_bit_be(void* addr, int bit)
|
static INLINE int test_bit_be(void* addr, int bit)
|
||||||
{
|
{
|
||||||
return !!(((uint8_t*)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
|
return !!(((uint8_t*)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
|
||||||
}
|
}
|
||||||
@ -1310,7 +1323,7 @@ static void bitmap_1be_32_to_32(uint8_t* dest, int dest_stride,
|
|||||||
uint32_t fore_color;
|
uint32_t fore_color;
|
||||||
uint32_t back_color;
|
uint32_t back_color;
|
||||||
|
|
||||||
spice_assert(palette != NULL);
|
ASSERT(palette != NULL);
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
return;
|
return;
|
||||||
@ -1342,7 +1355,7 @@ static void bitmap_1be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
uint16_t fore_color;
|
uint16_t fore_color;
|
||||||
uint16_t back_color;
|
uint16_t back_color;
|
||||||
|
|
||||||
spice_assert(palette != NULL);
|
ASSERT(palette != NULL);
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
return;
|
return;
|
||||||
@ -1367,25 +1380,6 @@ static void bitmap_1be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
|
|
||||||
#ifdef NOT_USED_ATM
|
#ifdef NOT_USED_ATM
|
||||||
|
|
||||||
static inline uint32_t rgb_16_555_to_32(uint16_t color)
|
|
||||||
{
|
|
||||||
uint32_t ret;
|
|
||||||
|
|
||||||
ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
|
|
||||||
ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
|
|
||||||
ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint16_t rgb_32_to_16_555(uint32_t color)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
(((color) >> 3) & 0x001f) |
|
|
||||||
(((color) >> 6) & 0x03e0) |
|
|
||||||
(((color) >> 9) & 0x7c00);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bitmap_16_to_32(uint8_t* dest, int dest_stride,
|
static void bitmap_16_to_32(uint8_t* dest, int dest_stride,
|
||||||
uint8_t* src, int src_stride,
|
uint8_t* src, int src_stride,
|
||||||
int width, uint8_t* end)
|
int width, uint8_t* end)
|
||||||
@ -1467,7 +1461,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
dest = (uint8_t *)pixman_image_get_data(dest_image);
|
dest = (uint8_t *)pixman_image_get_data(dest_image);
|
||||||
dest_stride = pixman_image_get_stride(dest_image);
|
dest_stride = pixman_image_get_stride(dest_image);
|
||||||
if (!(flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
if (!(flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
||||||
spice_assert(height > 0);
|
ASSERT(height > 0);
|
||||||
dest += dest_stride * (height - 1);
|
dest += dest_stride * (height - 1);
|
||||||
dest_stride = -dest_stride;
|
dest_stride = -dest_stride;
|
||||||
}
|
}
|
||||||
@ -1478,9 +1472,6 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
case SPICE_BITMAP_FMT_RGBA:
|
case SPICE_BITMAP_FMT_RGBA:
|
||||||
bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end);
|
bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end);
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_8BIT_A:
|
|
||||||
bitmap_8_to_8(dest, dest_stride, src, src_stride, width, end);
|
|
||||||
break;
|
|
||||||
case SPICE_BITMAP_FMT_24BIT:
|
case SPICE_BITMAP_FMT_24BIT:
|
||||||
bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end);
|
bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end);
|
||||||
break;
|
break;
|
||||||
@ -1494,7 +1485,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
||||||
bitmap_8_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
bitmap_8_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||||
} else {
|
} else {
|
||||||
spice_error("Unsupported palette format");
|
PANIC("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_4BIT_BE:
|
case SPICE_BITMAP_FMT_4BIT_BE:
|
||||||
@ -1504,7 +1495,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
||||||
bitmap_4be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
bitmap_4be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||||
} else {
|
} else {
|
||||||
spice_error("Unsupported palette format");
|
PANIC("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_1BIT_BE:
|
case SPICE_BITMAP_FMT_1BIT_BE:
|
||||||
@ -1514,11 +1505,11 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
||||||
bitmap_1be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
bitmap_1be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||||
} else {
|
} else {
|
||||||
spice_error("Unsupported palette format");
|
PANIC("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
spice_error("Unsupported bitmap format");
|
PANIC("Unsupported bitmap format");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,29 +16,20 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_PIXMAN_UTILS
|
#ifndef _H__PIXMAN_UTILS
|
||||||
#define H_SPICE_COMMON_PIXMAN_UTILS
|
#define _H__PIXMAN_UTILS
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/macros.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#define PIXMAN_DONT_DEFINE_STDINT
|
#define PIXMAN_DONT_DEFINE_STDINT
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef __cplusplus
|
||||||
# define PIXMAN_LE_x8r8g8b8 PIXMAN_b8g8r8x8
|
extern "C" {
|
||||||
# define PIXMAN_LE_a8r8g8b8 PIXMAN_b8g8r8a8
|
|
||||||
# define PIXMAN_LE_r8g8b8 PIXMAN_b8g8r8
|
|
||||||
#else
|
|
||||||
# define PIXMAN_LE_x8r8g8b8 PIXMAN_x8r8g8b8
|
|
||||||
# define PIXMAN_LE_a8r8g8b8 PIXMAN_a8r8g8b8
|
|
||||||
# define PIXMAN_LE_r8g8b8 PIXMAN_r8g8b8
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
|
||||||
|
|
||||||
/* This lists all possible 2 argument binary raster ops.
|
/* This lists all possible 2 argument binary raster ops.
|
||||||
* This enum has the same values as the X11 GXcopy type
|
* This enum has the same values as the X11 GXcopy type
|
||||||
* and same as the GL constants (GL_AND etc) if you
|
* and same as the GL constants (GL_AND etc) if you
|
||||||
@ -138,6 +129,8 @@ void spice_pixman_copy_rect(pixman_image_t *image,
|
|||||||
int w, int h,
|
int w, int h,
|
||||||
int dest_x, int dest_y);
|
int dest_x, int dest_y);
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // H_SPICE_COMMON_PIXMAN_UTILS
|
#endif /* _H__PIXMAN_UTILS */
|
||||||
|
|||||||
705
common/quic.c
705
common/quic.c
File diff suppressed because it is too large
Load Diff
@ -16,13 +16,14 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_QUIC
|
#ifndef __QUIC_H
|
||||||
#define H_SPICE_COMMON_QUIC
|
#define __QUIC_H
|
||||||
|
|
||||||
#include <spice/macros.h>
|
#include "quic_config.h"
|
||||||
#include "macros.h"
|
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QUIC_IMAGE_TYPE_INVALID,
|
QUIC_IMAGE_TYPE_INVALID,
|
||||||
@ -40,10 +41,9 @@ typedef void *QuicContext;
|
|||||||
|
|
||||||
typedef struct QuicUsrContext QuicUsrContext;
|
typedef struct QuicUsrContext QuicUsrContext;
|
||||||
struct QuicUsrContext {
|
struct QuicUsrContext {
|
||||||
SPICE_GNUC_NORETURN
|
void (*error)(QuicUsrContext *usr, const char *fmt, ...);
|
||||||
SPICE_GNUC_PRINTF(2, 3) void (*error)(QuicUsrContext *usr, const char *fmt, ...);
|
void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
|
||||||
SPICE_GNUC_PRINTF(2, 3) void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
|
void (*info)(QuicUsrContext *usr, const char *fmt, ...);
|
||||||
SPICE_GNUC_PRINTF(2, 3) void (*info)(QuicUsrContext *usr, const char *fmt, ...);
|
|
||||||
void *(*malloc)(QuicUsrContext *usr, int size);
|
void *(*malloc)(QuicUsrContext *usr, int size);
|
||||||
void (*free)(QuicUsrContext *usr, void *ptr);
|
void (*free)(QuicUsrContext *usr, void *ptr);
|
||||||
int (*more_space)(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed);
|
int (*more_space)(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed);
|
||||||
@ -63,6 +63,10 @@ int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride)
|
|||||||
QuicContext *quic_create(QuicUsrContext *usr);
|
QuicContext *quic_create(QuicUsrContext *usr);
|
||||||
void quic_destroy(QuicContext *quic);
|
void quic_destroy(QuicContext *quic);
|
||||||
|
|
||||||
SPICE_END_DECLS
|
void quic_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -16,13 +16,15 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_QUIC_CONFIG
|
#ifndef __QUIC_CONFIG_H
|
||||||
#define H_SPICE_COMMON_QUIC_CONFIG
|
#define __QUIC_CONFIG_H
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -39,6 +41,8 @@ SPICE_BEGIN_DECLS
|
|||||||
#endif // QXLDD
|
#endif // QXLDD
|
||||||
#endif //__GNUC__
|
#endif //__GNUC__
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -15,7 +15,9 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef QUIC_FAMILY_8BPC
|
#ifdef QUIC_FAMILY_8BPC
|
||||||
#undef QUIC_FAMILY_8BPC
|
#undef QUIC_FAMILY_8BPC
|
||||||
@ -32,19 +34,26 @@
|
|||||||
#define BPC 5
|
#define BPC 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline unsigned int FNAME(golomb_code)(const BYTE n, const unsigned int l)
|
|
||||||
|
static unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
|
||||||
{
|
{
|
||||||
return VNAME(family).golomb_code[n][l];
|
if (n < VNAME(family).nGRcodewords[l]) {
|
||||||
|
return (n >> l) + 1 + l;
|
||||||
|
} else {
|
||||||
|
return VNAME(family).notGRcwlen[l];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
|
static void FNAME(golomb_coding)(const BYTE n, const unsigned int l, unsigned int * const codeword,
|
||||||
|
unsigned int * const codewordlen)
|
||||||
{
|
{
|
||||||
return VNAME(family).golomb_code_len[n][l];
|
if (n < VNAME(family).nGRcodewords[l]) {
|
||||||
}
|
(*codeword) = bitat[l] | (n & bppmask[l]);
|
||||||
|
(*codewordlen) = (n >> l) + l + 1;
|
||||||
static void FNAME(golomb_coding)(Encoder *encoder, const BYTE n, const unsigned int l)
|
} else {
|
||||||
{
|
(*codeword) = n - VNAME(family).nGRcodewords[l];
|
||||||
encode(encoder, FNAME(golomb_code)(n, l), FNAME(golomb_code_len)(n, l));
|
(*codewordlen) = VNAME(family).notGRcwlen[l];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned int bits,
|
static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned int bits,
|
||||||
@ -65,16 +74,13 @@ static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned
|
|||||||
|
|
||||||
/* update the bucket using just encoded curval */
|
/* update the bucket using just encoded curval */
|
||||||
static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
|
static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
|
||||||
const BYTE curval)
|
const BYTE curval, unsigned int bpp)
|
||||||
{
|
{
|
||||||
SPICE_VERIFY(BPC >= 1);
|
|
||||||
spice_return_if_fail (bucket != NULL);
|
|
||||||
|
|
||||||
const unsigned int bpp = BPC;
|
|
||||||
COUNTER * const pcounters = bucket->pcounters;
|
COUNTER * const pcounters = bucket->pcounters;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int bestcode;
|
unsigned int bestcode;
|
||||||
unsigned int bestcodelen;
|
unsigned int bestcodelen;
|
||||||
|
//unsigned int bpp = encoder->bpp;
|
||||||
|
|
||||||
/* update counters, find minimum */
|
/* update counters, find minimum */
|
||||||
|
|
||||||
@ -101,14 +107,9 @@ static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
|
|||||||
|
|
||||||
static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
|
static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
|
||||||
{
|
{
|
||||||
spice_extra_assert(val < (0x1U << BPC));
|
ASSERT(channel->encoder->usr, val < (0x1U << BPC));
|
||||||
|
|
||||||
/* The and (&) here is to avoid buffer overflows in case of garbage or malicious
|
return channel->_buckets_ptrs[val];
|
||||||
* attempts. Is much faster then using comparisons and save us from such situations.
|
|
||||||
* Note that on normal build the check above won't be compiled as this code path
|
|
||||||
* is pretty hot and would cause speed regressions.
|
|
||||||
*/
|
|
||||||
return channel->_buckets_ptrs[val & ((1U << BPC) - 1)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef FNAME
|
#undef FNAME
|
||||||
|
|||||||
765
common/quic_rgb_tmpl.c
Normal file
765
common/quic_rgb_tmpl.c
Normal file
@ -0,0 +1,765 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QUIC_RGB32
|
||||||
|
#undef QUIC_RGB32
|
||||||
|
#define PIXEL rgb32_pixel_t
|
||||||
|
#define FNAME(name) quic_rgb32_##name
|
||||||
|
#define golomb_coding golomb_coding_8bpc
|
||||||
|
#define golomb_decoding golomb_decoding_8bpc
|
||||||
|
#define update_model update_model_8bpc
|
||||||
|
#define find_bucket find_bucket_8bpc
|
||||||
|
#define family family_8bpc
|
||||||
|
#define BPC 8
|
||||||
|
#define BPC_MASK 0xffU
|
||||||
|
#define COMPRESS_IMP
|
||||||
|
#define SET_r(pix, val) ((pix)->r = val)
|
||||||
|
#define GET_r(pix) ((pix)->r)
|
||||||
|
#define SET_g(pix, val) ((pix)->g = val)
|
||||||
|
#define GET_g(pix) ((pix)->g)
|
||||||
|
#define SET_b(pix, val) ((pix)->b = val)
|
||||||
|
#define GET_b(pix) ((pix)->b)
|
||||||
|
#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QUIC_RGB24
|
||||||
|
#undef QUIC_RGB24
|
||||||
|
#define PIXEL rgb24_pixel_t
|
||||||
|
#define FNAME(name) quic_rgb24_##name
|
||||||
|
#define golomb_coding golomb_coding_8bpc
|
||||||
|
#define golomb_decoding golomb_decoding_8bpc
|
||||||
|
#define update_model update_model_8bpc
|
||||||
|
#define find_bucket find_bucket_8bpc
|
||||||
|
#define family family_8bpc
|
||||||
|
#define BPC 8
|
||||||
|
#define BPC_MASK 0xffU
|
||||||
|
#define COMPRESS_IMP
|
||||||
|
#define SET_r(pix, val) ((pix)->r = val)
|
||||||
|
#define GET_r(pix) ((pix)->r)
|
||||||
|
#define SET_g(pix, val) ((pix)->g = val)
|
||||||
|
#define GET_g(pix) ((pix)->g)
|
||||||
|
#define SET_b(pix, val) ((pix)->b = val)
|
||||||
|
#define GET_b(pix) ((pix)->b)
|
||||||
|
#define UNCOMPRESS_PIX_START(pix)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QUIC_RGB16
|
||||||
|
#undef QUIC_RGB16
|
||||||
|
#define PIXEL rgb16_pixel_t
|
||||||
|
#define FNAME(name) quic_rgb16_##name
|
||||||
|
#define golomb_coding golomb_coding_5bpc
|
||||||
|
#define golomb_decoding golomb_decoding_5bpc
|
||||||
|
#define update_model update_model_5bpc
|
||||||
|
#define find_bucket find_bucket_5bpc
|
||||||
|
#define family family_5bpc
|
||||||
|
#define BPC 5
|
||||||
|
#define BPC_MASK 0x1fU
|
||||||
|
#define COMPRESS_IMP
|
||||||
|
#define SET_r(pix, val) (*(pix) = (*(pix) & ~(0x1f << 10)) | ((val) << 10))
|
||||||
|
#define GET_r(pix) ((*(pix) >> 10) & 0x1f)
|
||||||
|
#define SET_g(pix, val) (*(pix) = (*(pix) & ~(0x1f << 5)) | ((val) << 5))
|
||||||
|
#define GET_g(pix) ((*(pix) >> 5) & 0x1f)
|
||||||
|
#define SET_b(pix, val) (*(pix) = (*(pix) & ~0x1f) | (val))
|
||||||
|
#define GET_b(pix) (*(pix) & 0x1f)
|
||||||
|
#define UNCOMPRESS_PIX_START(pix) (*(pix) = 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QUIC_RGB16_TO_32
|
||||||
|
#undef QUIC_RGB16_TO_32
|
||||||
|
#define PIXEL rgb32_pixel_t
|
||||||
|
#define FNAME(name) quic_rgb16_to_32_##name
|
||||||
|
#define golomb_coding golomb_coding_5bpc
|
||||||
|
#define golomb_decoding golomb_decoding_5bpc
|
||||||
|
#define update_model update_model_5bpc
|
||||||
|
#define find_bucket find_bucket_5bpc
|
||||||
|
#define family family_5bpc
|
||||||
|
#define BPC 5
|
||||||
|
#define BPC_MASK 0x1fU
|
||||||
|
|
||||||
|
#define SET_r(pix, val) ((pix)->r = ((val) << 3) | (((val) & 0x1f) >> 2))
|
||||||
|
#define GET_r(pix) ((pix)->r >> 3)
|
||||||
|
#define SET_g(pix, val) ((pix)->g = ((val) << 3) | (((val) & 0x1f) >> 2))
|
||||||
|
#define GET_g(pix) ((pix)->g >> 3)
|
||||||
|
#define SET_b(pix, val) ((pix)->b = ((val) << 3) | (((val) & 0x1f) >> 2))
|
||||||
|
#define GET_b(pix) ((pix)->b >> 3)
|
||||||
|
#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SAME_PIXEL(p1, p2) \
|
||||||
|
(GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
|
||||||
|
GET_b(p1) == GET_b(p2))
|
||||||
|
|
||||||
|
|
||||||
|
#define _PIXEL_A(channel, curr) ((unsigned int)GET_##channel((curr) - 1))
|
||||||
|
#define _PIXEL_B(channel, prev) ((unsigned int)GET_##channel(prev))
|
||||||
|
#define _PIXEL_C(channel, prev) ((unsigned int)GET_##channel((prev) - 1))
|
||||||
|
|
||||||
|
/* a */
|
||||||
|
|
||||||
|
#define DECORELATE_0(channel, curr, bpc_mask)\
|
||||||
|
family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)_PIXEL_A(channel, curr)) & bpc_mask]
|
||||||
|
|
||||||
|
#define CORELATE_0(channel, curr, correlate, bpc_mask)\
|
||||||
|
((family.xlatL2U[correlate] + _PIXEL_A(channel, curr)) & bpc_mask)
|
||||||
|
|
||||||
|
#ifdef PRED_1
|
||||||
|
|
||||||
|
/* (a+b)/2 */
|
||||||
|
#define DECORELATE(channel, prev, curr, bpc_mask, r) \
|
||||||
|
r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)((_PIXEL_A(channel, curr) + \
|
||||||
|
_PIXEL_B(channel, prev)) >> 1)) & bpc_mask]
|
||||||
|
|
||||||
|
#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) \
|
||||||
|
SET_##channel(r, ((family.xlatL2U[correlate] + \
|
||||||
|
(int)((_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev)) >> 1)) & bpc_mask))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PRED_2
|
||||||
|
|
||||||
|
/* .75a+.75b-.5c */
|
||||||
|
#define DECORELATE(channel, prev, curr, bpc_mask, r) { \
|
||||||
|
int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) - \
|
||||||
|
(int)(_PIXEL_C(channel, prev) << 1)) >> 2; \
|
||||||
|
if (p < 0) { \
|
||||||
|
p = 0; \
|
||||||
|
} else if ((unsigned)p > bpc_mask) { \
|
||||||
|
p = bpc_mask; \
|
||||||
|
} \
|
||||||
|
r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - p) & bpc_mask]; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) { \
|
||||||
|
const int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) - \
|
||||||
|
(int)(_PIXEL_C(channel, prev) << 1) ) >> 2; \
|
||||||
|
const unsigned int s = family.xlatL2U[correlate]; \
|
||||||
|
if (!(p & ~bpc_mask)) { \
|
||||||
|
SET_##channel(r, (s + (unsigned)p) & bpc_mask); \
|
||||||
|
} else if (p < 0) { \
|
||||||
|
SET_##channel(r, s); \
|
||||||
|
} else { \
|
||||||
|
SET_##channel(r, (s + bpc_mask) & bpc_mask); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define COMPRESS_ONE_ROW0_0(channel) \
|
||||||
|
correlate_row_##channel[0] = family.xlatU2L[GET_##channel(cur_row)]; \
|
||||||
|
golomb_coding(correlate_row_##channel[0], find_bucket(channel_##channel, \
|
||||||
|
correlate_row_##channel[-1])->bestcode, \
|
||||||
|
&codeword, &codewordlen); \
|
||||||
|
encode(encoder, codeword, codewordlen);
|
||||||
|
|
||||||
|
#define COMPRESS_ONE_ROW0(channel, index) \
|
||||||
|
correlate_row_##channel[index] = DECORELATE_0(channel, &cur_row[index], bpc_mask); \
|
||||||
|
golomb_coding(correlate_row_##channel[index], find_bucket(channel_##channel, \
|
||||||
|
correlate_row_##channel[index -1])->bestcode, \
|
||||||
|
&codeword, &codewordlen); \
|
||||||
|
encode(encoder, codeword, codewordlen);
|
||||||
|
|
||||||
|
#define UPDATE_MODEL(index) \
|
||||||
|
update_model(&encoder->rgb_state, find_bucket(channel_r, correlate_row_r[index - 1]), \
|
||||||
|
correlate_row_r[index], bpc); \
|
||||||
|
update_model(&encoder->rgb_state, find_bucket(channel_g, correlate_row_g[index - 1]), \
|
||||||
|
correlate_row_g[index], bpc); \
|
||||||
|
update_model(&encoder->rgb_state, find_bucket(channel_b, correlate_row_b[index - 1]), \
|
||||||
|
correlate_row_b[index], bpc);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef RLE_PRED_1
|
||||||
|
#define RLE_PRED_1_IMP \
|
||||||
|
if (SAME_PIXEL(&cur_row[i - 1], &prev_row[i])) { \
|
||||||
|
if (run_index != i && SAME_PIXEL(&prev_row[i - 1], &prev_row[i]) && \
|
||||||
|
i + 1 < end && SAME_PIXEL(&prev_row[i], &prev_row[i + 1])) { \
|
||||||
|
goto do_run; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define RLE_PRED_1_IMP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RLE_PRED_2
|
||||||
|
#define RLE_PRED_2_IMP \
|
||||||
|
if (SAME_PIXEL(&prev_row[i - 1], &prev_row[i])) { \
|
||||||
|
if (run_index != i && i > 2 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2])) { \
|
||||||
|
goto do_run; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define RLE_PRED_2_IMP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RLE_PRED_3
|
||||||
|
#define RLE_PRED_3_IMP \
|
||||||
|
if (i > 1 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2]) && i != run_index) { \
|
||||||
|
goto do_run; \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define RLE_PRED_3_IMP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef COMPRESS_IMP
|
||||||
|
|
||||||
|
static void FNAME(compress_row0_seg)(Encoder *encoder, int i,
|
||||||
|
const PIXEL * const cur_row,
|
||||||
|
const int end,
|
||||||
|
const unsigned int waitmask,
|
||||||
|
const unsigned int bpc,
|
||||||
|
const unsigned int bpc_mask)
|
||||||
|
{
|
||||||
|
Channel * const channel_r = encoder->channels;
|
||||||
|
Channel * const channel_g = channel_r + 1;
|
||||||
|
Channel * const channel_b = channel_g + 1;
|
||||||
|
|
||||||
|
BYTE * const correlate_row_r = channel_r->correlate_row;
|
||||||
|
BYTE * const correlate_row_g = channel_g->correlate_row;
|
||||||
|
BYTE * const correlate_row_b = channel_b->correlate_row;
|
||||||
|
int stopidx;
|
||||||
|
|
||||||
|
ASSERT(encoder->usr, end - i > 0);
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
unsigned int codeword, codewordlen;
|
||||||
|
|
||||||
|
COMPRESS_ONE_ROW0_0(r);
|
||||||
|
COMPRESS_ONE_ROW0_0(g);
|
||||||
|
COMPRESS_ONE_ROW0_0(b);
|
||||||
|
|
||||||
|
if (encoder->rgb_state.waitcnt) {
|
||||||
|
encoder->rgb_state.waitcnt--;
|
||||||
|
} else {
|
||||||
|
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
||||||
|
UPDATE_MODEL(0);
|
||||||
|
}
|
||||||
|
stopidx = ++i + encoder->rgb_state.waitcnt;
|
||||||
|
} else {
|
||||||
|
stopidx = i + encoder->rgb_state.waitcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (stopidx < end) {
|
||||||
|
for (; i <= stopidx; i++) {
|
||||||
|
unsigned int codeword, codewordlen;
|
||||||
|
COMPRESS_ONE_ROW0(r, i);
|
||||||
|
COMPRESS_ONE_ROW0(g, i);
|
||||||
|
COMPRESS_ONE_ROW0(b, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
UPDATE_MODEL(stopidx);
|
||||||
|
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < end; i++) {
|
||||||
|
unsigned int codeword, codewordlen;
|
||||||
|
|
||||||
|
COMPRESS_ONE_ROW0(r, i);
|
||||||
|
COMPRESS_ONE_ROW0(g, i);
|
||||||
|
COMPRESS_ONE_ROW0(b, i);
|
||||||
|
}
|
||||||
|
encoder->rgb_state.waitcnt = stopidx - end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FNAME(compress_row0)(Encoder *encoder, const PIXEL *cur_row,
|
||||||
|
unsigned int width)
|
||||||
|
{
|
||||||
|
const unsigned int bpc = BPC;
|
||||||
|
const unsigned int bpc_mask = BPC_MASK;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
|
||||||
|
if (encoder->rgb_state.wmileft) {
|
||||||
|
FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + encoder->rgb_state.wmileft,
|
||||||
|
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
|
||||||
|
width -= encoder->rgb_state.wmileft;
|
||||||
|
pos += encoder->rgb_state.wmileft;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->rgb_state.wmidx++;
|
||||||
|
set_wm_trigger(&encoder->rgb_state);
|
||||||
|
encoder->rgb_state.wmileft = wminext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) {
|
||||||
|
FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + width,
|
||||||
|
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
|
||||||
|
if (wmimax > (int)encoder->rgb_state.wmidx) {
|
||||||
|
encoder->rgb_state.wmileft -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
|
||||||
|
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
|
||||||
|
ASSERT(encoder->usr, wminext > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COMPRESS_ONE_0(channel) \
|
||||||
|
correlate_row_##channel[0] = family.xlatU2L[(unsigned)((int)GET_##channel(cur_row) - \
|
||||||
|
(int)GET_##channel(prev_row) ) & bpc_mask]; \
|
||||||
|
golomb_coding(correlate_row_##channel[0], \
|
||||||
|
find_bucket(channel_##channel, correlate_row_##channel[-1])->bestcode, \
|
||||||
|
&codeword, &codewordlen); \
|
||||||
|
encode(encoder, codeword, codewordlen);
|
||||||
|
|
||||||
|
#define COMPRESS_ONE(channel, index) \
|
||||||
|
DECORELATE(channel, &prev_row[index], &cur_row[index],bpc_mask, \
|
||||||
|
correlate_row_##channel[index]); \
|
||||||
|
golomb_coding(correlate_row_##channel[index], \
|
||||||
|
find_bucket(channel_##channel, correlate_row_##channel[index - 1])->bestcode, \
|
||||||
|
&codeword, &codewordlen); \
|
||||||
|
encode(encoder, codeword, codewordlen);
|
||||||
|
|
||||||
|
static void FNAME(compress_row_seg)(Encoder *encoder, int i,
|
||||||
|
const PIXEL * const prev_row,
|
||||||
|
const PIXEL * const cur_row,
|
||||||
|
const int end,
|
||||||
|
const unsigned int waitmask,
|
||||||
|
const unsigned int bpc,
|
||||||
|
const unsigned int bpc_mask)
|
||||||
|
{
|
||||||
|
Channel * const channel_r = encoder->channels;
|
||||||
|
Channel * const channel_g = channel_r + 1;
|
||||||
|
Channel * const channel_b = channel_g + 1;
|
||||||
|
|
||||||
|
BYTE * const correlate_row_r = channel_r->correlate_row;
|
||||||
|
BYTE * const correlate_row_g = channel_g->correlate_row;
|
||||||
|
BYTE * const correlate_row_b = channel_b->correlate_row;
|
||||||
|
int stopidx;
|
||||||
|
#ifdef RLE
|
||||||
|
int run_index = 0;
|
||||||
|
int run_size;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ASSERT(encoder->usr, end - i > 0);
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
unsigned int codeword, codewordlen;
|
||||||
|
|
||||||
|
COMPRESS_ONE_0(r);
|
||||||
|
COMPRESS_ONE_0(g);
|
||||||
|
COMPRESS_ONE_0(b);
|
||||||
|
|
||||||
|
if (encoder->rgb_state.waitcnt) {
|
||||||
|
encoder->rgb_state.waitcnt--;
|
||||||
|
} else {
|
||||||
|
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
||||||
|
UPDATE_MODEL(0);
|
||||||
|
}
|
||||||
|
stopidx = ++i + encoder->rgb_state.waitcnt;
|
||||||
|
} else {
|
||||||
|
stopidx = i + encoder->rgb_state.waitcnt;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
while (stopidx < end) {
|
||||||
|
for (; i <= stopidx; i++) {
|
||||||
|
unsigned int codeword, codewordlen;
|
||||||
|
#ifdef RLE
|
||||||
|
RLE_PRED_1_IMP;
|
||||||
|
RLE_PRED_2_IMP;
|
||||||
|
RLE_PRED_3_IMP;
|
||||||
|
#endif
|
||||||
|
COMPRESS_ONE(r, i);
|
||||||
|
COMPRESS_ONE(g, i);
|
||||||
|
COMPRESS_ONE(b, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
UPDATE_MODEL(stopidx);
|
||||||
|
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < end; i++) {
|
||||||
|
unsigned int codeword, codewordlen;
|
||||||
|
#ifdef RLE
|
||||||
|
RLE_PRED_1_IMP;
|
||||||
|
RLE_PRED_2_IMP;
|
||||||
|
RLE_PRED_3_IMP;
|
||||||
|
#endif
|
||||||
|
COMPRESS_ONE(r, i);
|
||||||
|
COMPRESS_ONE(g, i);
|
||||||
|
COMPRESS_ONE(b, i);
|
||||||
|
}
|
||||||
|
encoder->rgb_state.waitcnt = stopidx - end;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef RLE
|
||||||
|
do_run:
|
||||||
|
run_index = i;
|
||||||
|
encoder->rgb_state.waitcnt = stopidx - i;
|
||||||
|
run_size = 0;
|
||||||
|
|
||||||
|
while (SAME_PIXEL(&cur_row[i], &cur_row[i - 1])) {
|
||||||
|
run_size++;
|
||||||
|
if (++i == end) {
|
||||||
|
encode_run(encoder, run_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
encode_run(encoder, run_size);
|
||||||
|
stopidx = i + encoder->rgb_state.waitcnt;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FNAME(compress_row)(Encoder *encoder,
|
||||||
|
const PIXEL * const prev_row,
|
||||||
|
const PIXEL * const cur_row,
|
||||||
|
unsigned int width)
|
||||||
|
|
||||||
|
{
|
||||||
|
const unsigned int bpc = BPC;
|
||||||
|
const unsigned int bpc_mask = BPC_MASK;
|
||||||
|
unsigned int pos = 0;
|
||||||
|
|
||||||
|
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
|
||||||
|
if (encoder->rgb_state.wmileft) {
|
||||||
|
FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row,
|
||||||
|
pos + encoder->rgb_state.wmileft,
|
||||||
|
bppmask[encoder->rgb_state.wmidx],
|
||||||
|
bpc, bpc_mask);
|
||||||
|
width -= encoder->rgb_state.wmileft;
|
||||||
|
pos += encoder->rgb_state.wmileft;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->rgb_state.wmidx++;
|
||||||
|
set_wm_trigger(&encoder->rgb_state);
|
||||||
|
encoder->rgb_state.wmileft = wminext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) {
|
||||||
|
FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row, pos + width,
|
||||||
|
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
|
||||||
|
if (wmimax > (int)encoder->rgb_state.wmidx) {
|
||||||
|
encoder->rgb_state.wmileft -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
|
||||||
|
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
|
||||||
|
ASSERT(encoder->usr, wminext > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UNCOMPRESS_ONE_ROW0_0(channel) \
|
||||||
|
correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
|
||||||
|
correlate_row_##channel[-1])->bestcode, \
|
||||||
|
encoder->io_word, &codewordlen); \
|
||||||
|
SET_##channel(&cur_row[0], (BYTE)family.xlatL2U[correlate_row_##channel[0]]); \
|
||||||
|
decode_eatbits(encoder, codewordlen);
|
||||||
|
|
||||||
|
#define UNCOMPRESS_ONE_ROW0(channel) \
|
||||||
|
correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
|
||||||
|
correlate_row_##channel[i - 1])->bestcode, \
|
||||||
|
encoder->io_word, \
|
||||||
|
&codewordlen); \
|
||||||
|
SET_##channel(&cur_row[i], CORELATE_0(channel, &cur_row[i], correlate_row_##channel[i], \
|
||||||
|
bpc_mask)); \
|
||||||
|
decode_eatbits(encoder, codewordlen);
|
||||||
|
|
||||||
|
static void FNAME(uncompress_row0_seg)(Encoder *encoder, int i,
|
||||||
|
PIXEL * const cur_row,
|
||||||
|
const int end,
|
||||||
|
const unsigned int waitmask,
|
||||||
|
const unsigned int bpc,
|
||||||
|
const unsigned int bpc_mask)
|
||||||
|
{
|
||||||
|
Channel * const channel_r = encoder->channels;
|
||||||
|
Channel * const channel_g = channel_r + 1;
|
||||||
|
Channel * const channel_b = channel_g + 1;
|
||||||
|
|
||||||
|
BYTE * const correlate_row_r = channel_r->correlate_row;
|
||||||
|
BYTE * const correlate_row_g = channel_g->correlate_row;
|
||||||
|
BYTE * const correlate_row_b = channel_b->correlate_row;
|
||||||
|
int stopidx;
|
||||||
|
|
||||||
|
ASSERT(encoder->usr, end - i > 0);
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
UNCOMPRESS_ONE_ROW0_0(r);
|
||||||
|
UNCOMPRESS_ONE_ROW0_0(g);
|
||||||
|
UNCOMPRESS_ONE_ROW0_0(b);
|
||||||
|
|
||||||
|
if (encoder->rgb_state.waitcnt) {
|
||||||
|
--encoder->rgb_state.waitcnt;
|
||||||
|
} else {
|
||||||
|
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
||||||
|
UPDATE_MODEL(0);
|
||||||
|
}
|
||||||
|
stopidx = ++i + encoder->rgb_state.waitcnt;
|
||||||
|
} else {
|
||||||
|
stopidx = i + encoder->rgb_state.waitcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (stopidx < end) {
|
||||||
|
for (; i <= stopidx; i++) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
UNCOMPRESS_ONE_ROW0(r);
|
||||||
|
UNCOMPRESS_ONE_ROW0(g);
|
||||||
|
UNCOMPRESS_ONE_ROW0(b);
|
||||||
|
}
|
||||||
|
UPDATE_MODEL(stopidx);
|
||||||
|
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < end; i++) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
UNCOMPRESS_ONE_ROW0(r);
|
||||||
|
UNCOMPRESS_ONE_ROW0(g);
|
||||||
|
UNCOMPRESS_ONE_ROW0(b);
|
||||||
|
}
|
||||||
|
encoder->rgb_state.waitcnt = stopidx - end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FNAME(uncompress_row0)(Encoder *encoder,
|
||||||
|
PIXEL * const cur_row,
|
||||||
|
unsigned int width)
|
||||||
|
|
||||||
|
{
|
||||||
|
const unsigned int bpc = BPC;
|
||||||
|
const unsigned int bpc_mask = BPC_MASK;
|
||||||
|
unsigned int pos = 0;
|
||||||
|
|
||||||
|
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
|
||||||
|
if (encoder->rgb_state.wmileft) {
|
||||||
|
FNAME(uncompress_row0_seg)(encoder, pos, cur_row,
|
||||||
|
pos + encoder->rgb_state.wmileft,
|
||||||
|
bppmask[encoder->rgb_state.wmidx],
|
||||||
|
bpc, bpc_mask);
|
||||||
|
pos += encoder->rgb_state.wmileft;
|
||||||
|
width -= encoder->rgb_state.wmileft;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->rgb_state.wmidx++;
|
||||||
|
set_wm_trigger(&encoder->rgb_state);
|
||||||
|
encoder->rgb_state.wmileft = wminext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) {
|
||||||
|
FNAME(uncompress_row0_seg)(encoder, pos, cur_row, pos + width,
|
||||||
|
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
|
||||||
|
if (wmimax > (int)encoder->rgb_state.wmidx) {
|
||||||
|
encoder->rgb_state.wmileft -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
|
||||||
|
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
|
||||||
|
ASSERT(encoder->usr, wminext > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNCOMPRESS_ONE_0(channel) \
|
||||||
|
correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
|
||||||
|
correlate_row_##channel[-1])->bestcode, \
|
||||||
|
encoder->io_word, &codewordlen); \
|
||||||
|
SET_##channel(&cur_row[0], (family.xlatL2U[correlate_row_##channel[0]] + \
|
||||||
|
GET_##channel(prev_row)) & bpc_mask); \
|
||||||
|
decode_eatbits(encoder, codewordlen);
|
||||||
|
|
||||||
|
#define UNCOMPRESS_ONE(channel) \
|
||||||
|
correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
|
||||||
|
correlate_row_##channel[i - 1])->bestcode, \
|
||||||
|
encoder->io_word, \
|
||||||
|
&codewordlen); \
|
||||||
|
CORELATE(channel, &prev_row[i], &cur_row[i], correlate_row_##channel[i], bpc_mask, \
|
||||||
|
&cur_row[i]); \
|
||||||
|
decode_eatbits(encoder, codewordlen);
|
||||||
|
|
||||||
|
static void FNAME(uncompress_row_seg)(Encoder *encoder,
|
||||||
|
const PIXEL * const prev_row,
|
||||||
|
PIXEL * const cur_row,
|
||||||
|
int i,
|
||||||
|
const int end,
|
||||||
|
const unsigned int bpc,
|
||||||
|
const unsigned int bpc_mask)
|
||||||
|
{
|
||||||
|
Channel * const channel_r = encoder->channels;
|
||||||
|
Channel * const channel_g = channel_r + 1;
|
||||||
|
Channel * const channel_b = channel_g + 1;
|
||||||
|
|
||||||
|
BYTE * const correlate_row_r = channel_r->correlate_row;
|
||||||
|
BYTE * const correlate_row_g = channel_g->correlate_row;
|
||||||
|
BYTE * const correlate_row_b = channel_b->correlate_row;
|
||||||
|
const unsigned int waitmask = bppmask[encoder->rgb_state.wmidx];
|
||||||
|
int stopidx;
|
||||||
|
#ifdef RLE
|
||||||
|
int run_index = 0;
|
||||||
|
int run_end;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ASSERT(encoder->usr, end - i > 0);
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
UNCOMPRESS_ONE_0(r);
|
||||||
|
UNCOMPRESS_ONE_0(g);
|
||||||
|
UNCOMPRESS_ONE_0(b);
|
||||||
|
|
||||||
|
if (encoder->rgb_state.waitcnt) {
|
||||||
|
--encoder->rgb_state.waitcnt;
|
||||||
|
} else {
|
||||||
|
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
||||||
|
UPDATE_MODEL(0);
|
||||||
|
}
|
||||||
|
stopidx = ++i + encoder->rgb_state.waitcnt;
|
||||||
|
} else {
|
||||||
|
stopidx = i + encoder->rgb_state.waitcnt;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
while (stopidx < end) {
|
||||||
|
for (; i <= stopidx; i++) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
#ifdef RLE
|
||||||
|
RLE_PRED_1_IMP;
|
||||||
|
RLE_PRED_2_IMP;
|
||||||
|
RLE_PRED_3_IMP;
|
||||||
|
#endif
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
UNCOMPRESS_ONE(r);
|
||||||
|
UNCOMPRESS_ONE(g);
|
||||||
|
UNCOMPRESS_ONE(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
UPDATE_MODEL(stopidx);
|
||||||
|
|
||||||
|
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < end; i++) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
#ifdef RLE
|
||||||
|
RLE_PRED_1_IMP;
|
||||||
|
RLE_PRED_2_IMP;
|
||||||
|
RLE_PRED_3_IMP;
|
||||||
|
#endif
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
UNCOMPRESS_ONE(r);
|
||||||
|
UNCOMPRESS_ONE(g);
|
||||||
|
UNCOMPRESS_ONE(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->rgb_state.waitcnt = stopidx - end;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef RLE
|
||||||
|
do_run:
|
||||||
|
encoder->rgb_state.waitcnt = stopidx - i;
|
||||||
|
run_index = i;
|
||||||
|
run_end = i + decode_run(encoder);
|
||||||
|
|
||||||
|
for (; i < run_end; i++) {
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
SET_r(&cur_row[i], GET_r(&cur_row[i - 1]));
|
||||||
|
SET_g(&cur_row[i], GET_g(&cur_row[i - 1]));
|
||||||
|
SET_b(&cur_row[i], GET_b(&cur_row[i - 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopidx = i + encoder->rgb_state.waitcnt;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FNAME(uncompress_row)(Encoder *encoder,
|
||||||
|
const PIXEL * const prev_row,
|
||||||
|
PIXEL * const cur_row,
|
||||||
|
unsigned int width)
|
||||||
|
|
||||||
|
{
|
||||||
|
const unsigned int bpc = BPC;
|
||||||
|
const unsigned int bpc_mask = BPC_MASK;
|
||||||
|
unsigned int pos = 0;
|
||||||
|
|
||||||
|
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
|
||||||
|
if (encoder->rgb_state.wmileft) {
|
||||||
|
FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
|
||||||
|
pos + encoder->rgb_state.wmileft, bpc, bpc_mask);
|
||||||
|
pos += encoder->rgb_state.wmileft;
|
||||||
|
width -= encoder->rgb_state.wmileft;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->rgb_state.wmidx++;
|
||||||
|
set_wm_trigger(&encoder->rgb_state);
|
||||||
|
encoder->rgb_state.wmileft = wminext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) {
|
||||||
|
FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
|
||||||
|
pos + width, bpc, bpc_mask);
|
||||||
|
if (wmimax > (int)encoder->rgb_state.wmidx) {
|
||||||
|
encoder->rgb_state.wmileft -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
|
||||||
|
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
|
||||||
|
ASSERT(encoder->usr, wminext > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef PIXEL
|
||||||
|
#undef FNAME
|
||||||
|
#undef _PIXEL_A
|
||||||
|
#undef _PIXEL_B
|
||||||
|
#undef _PIXEL_C
|
||||||
|
#undef SAME_PIXEL
|
||||||
|
#undef RLE_PRED_1_IMP
|
||||||
|
#undef RLE_PRED_2_IMP
|
||||||
|
#undef RLE_PRED_3_IMP
|
||||||
|
#undef UPDATE_MODEL
|
||||||
|
#undef DECORELATE_0
|
||||||
|
#undef DECORELATE
|
||||||
|
#undef COMPRESS_ONE_ROW0_0
|
||||||
|
#undef COMPRESS_ONE_ROW0
|
||||||
|
#undef COMPRESS_ONE_0
|
||||||
|
#undef COMPRESS_ONE
|
||||||
|
#undef CORELATE_0
|
||||||
|
#undef CORELATE
|
||||||
|
#undef UNCOMPRESS_ONE_ROW0_0
|
||||||
|
#undef UNCOMPRESS_ONE_ROW0
|
||||||
|
#undef UNCOMPRESS_ONE_0
|
||||||
|
#undef UNCOMPRESS_ONE
|
||||||
|
#undef golomb_coding
|
||||||
|
#undef golomb_decoding
|
||||||
|
#undef update_model
|
||||||
|
#undef find_bucket
|
||||||
|
#undef family
|
||||||
|
#undef BPC
|
||||||
|
#undef BPC_MASK
|
||||||
|
#undef COMPRESS_IMP
|
||||||
|
#undef SET_r
|
||||||
|
#undef GET_r
|
||||||
|
#undef SET_g
|
||||||
|
#undef GET_g
|
||||||
|
#undef SET_b
|
||||||
|
#undef GET_b
|
||||||
|
#undef UNCOMPRESS_PIX_START
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
|||||||
Subproject commit d5cbf6caba60d580401c72d0cd18c316cf1be211
|
|
||||||
@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2018 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/* This file include recorder library headers or if disabled provide
|
|
||||||
* replacement declarations */
|
|
||||||
|
|
||||||
#ifdef ENABLE_RECORDER
|
|
||||||
#include <common/recorder/recorder.h>
|
|
||||||
|
|
||||||
#elif defined(ENABLE_AGENT_INTERFACE)
|
|
||||||
#include <common/agent_interface.h>
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
/* Replacement declarations.
|
|
||||||
* There declarations should generate no code (beside when no optimization are
|
|
||||||
* selected) but catch some possible programming warnings/errors at
|
|
||||||
* compile/link time like:
|
|
||||||
* - usage of undeclared recorders;
|
|
||||||
* - recording formats and arguments;
|
|
||||||
* - matching RECORD_TIMING_BEGIN and RECORD_TIMING_END.
|
|
||||||
* The only exceptions are tweaks which just generate a variable to hold the
|
|
||||||
* value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct SpiceEmptyStruct {
|
|
||||||
char dummy[0];
|
|
||||||
} SpiceEmptyStruct;
|
|
||||||
|
|
||||||
typedef struct SpiceDummyTweak {
|
|
||||||
intptr_t tweak_value;
|
|
||||||
} SpiceDummyTweak;
|
|
||||||
|
|
||||||
#define RECORDER_DECLARE(rec) \
|
|
||||||
extern const SpiceEmptyStruct spice_recorder_ ## rec
|
|
||||||
#define RECORDER(rec, num_rings, comment) \
|
|
||||||
RECORDER_DEFINE(rec, num_rings, comment)
|
|
||||||
#define RECORDER_DEFINE(rec, num_rings, comment) \
|
|
||||||
const SpiceEmptyStruct SPICE_GNUC_UNUSED spice_recorder_ ## rec = {}
|
|
||||||
#define RECORDER_TRACE(rec) \
|
|
||||||
(sizeof(spice_recorder_ ## rec) != sizeof(SpiceEmptyStruct))
|
|
||||||
#define RECORDER_TWEAK_DECLARE(rec) \
|
|
||||||
extern const SpiceDummyTweak spice_recorder_tweak_ ## rec
|
|
||||||
#define RECORDER_TWEAK_DEFINE(rec, value, comment) \
|
|
||||||
const SpiceDummyTweak spice_recorder_tweak_ ## rec = { (value) }
|
|
||||||
#define RECORDER_TWEAK(rec) \
|
|
||||||
((spice_recorder_tweak_ ## rec).tweak_value)
|
|
||||||
#define RECORD(rec, ...) do { \
|
|
||||||
if (sizeof((spice_recorder_ ## rec).dummy)) printf(__VA_ARGS__); \
|
|
||||||
} while(0)
|
|
||||||
#define RECORD_TIMING_BEGIN(rec) \
|
|
||||||
do { RECORD(rec, "begin");
|
|
||||||
#define RECORD_TIMING_END(rec, op, name, value) \
|
|
||||||
RECORD(rec, "end" op name); \
|
|
||||||
} while(0)
|
|
||||||
#define record(...) \
|
|
||||||
RECORD(__VA_ARGS__)
|
|
||||||
static inline void
|
|
||||||
recorder_dump_on_common_signals(unsigned add, unsigned remove)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(ENABLE_AGENT_INTERFACE)
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
/* Stubs for Agent-Interface specific definitions */
|
|
||||||
static inline void
|
|
||||||
agent_interface_start(unsigned int port)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (*forward_quality_cb_t)(void *, const char *);
|
|
||||||
static inline void
|
|
||||||
agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef int (*on_connect_cb_t)(void *);
|
|
||||||
static inline void
|
|
||||||
agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
|
||||||
#endif
|
|
||||||
@ -16,16 +16,17 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_RECT
|
#ifndef _H_RECT
|
||||||
#define H_SPICE_COMMON_RECT
|
#define _H_RECT
|
||||||
|
|
||||||
#include <spice/macros.h>
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "log.h"
|
#include <spice/macros.h>
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void rect_sect(SpiceRect* r, const SpiceRect* bounds)
|
static INLINE void rect_sect(SpiceRect* r, const SpiceRect* bounds)
|
||||||
{
|
{
|
||||||
r->left = MAX(r->left, bounds->left);
|
r->left = MAX(r->left, bounds->left);
|
||||||
r->right = MIN(r->right, bounds->right);
|
r->right = MIN(r->right, bounds->right);
|
||||||
@ -36,7 +37,7 @@ static inline void rect_sect(SpiceRect* r, const SpiceRect* bounds)
|
|||||||
r->bottom = MAX(r->top, r->bottom);
|
r->bottom = MAX(r->top, r->bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void rect_offset(SpiceRect* r, int dx, int dy)
|
static INLINE void rect_offset(SpiceRect* r, int dx, int dy)
|
||||||
{
|
{
|
||||||
r->left += dx;
|
r->left += dx;
|
||||||
r->right += dx;
|
r->right += dx;
|
||||||
@ -44,24 +45,24 @@ static inline void rect_offset(SpiceRect* r, int dx, int dy)
|
|||||||
r->bottom += dy;
|
r->bottom += dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rect_is_empty(const SpiceRect* r)
|
static INLINE int rect_is_empty(const SpiceRect* r)
|
||||||
{
|
{
|
||||||
return r->top == r->bottom || r->left == r->right;
|
return r->top == r->bottom || r->left == r->right;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rect_intersects(const SpiceRect* r1, const SpiceRect* r2)
|
static INLINE int rect_intersects(const SpiceRect* r1, const SpiceRect* r2)
|
||||||
{
|
{
|
||||||
return r1->left < r2->right && r1->right > r2->left &&
|
return r1->left < r2->right && r1->right > r2->left &&
|
||||||
r1->top < r2->bottom && r1->bottom > r2->top;
|
r1->top < r2->bottom && r1->bottom > r2->top;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rect_is_equal(const SpiceRect *r1, const SpiceRect *r2)
|
static INLINE int rect_is_equal(const SpiceRect *r1, const SpiceRect *r2)
|
||||||
{
|
{
|
||||||
return r1->top == r2->top && r1->left == r2->left &&
|
return r1->top == r2->top && r1->left == r2->left &&
|
||||||
r1->bottom == r2->bottom && r1->right == r2->right;
|
r1->bottom == r2->bottom && r1->right == r2->right;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void rect_union(SpiceRect *dest, const SpiceRect *r)
|
static INLINE void rect_union(SpiceRect *dest, const SpiceRect *r)
|
||||||
{
|
{
|
||||||
dest->top = MIN(dest->top, r->top);
|
dest->top = MIN(dest->top, r->top);
|
||||||
dest->left = MIN(dest->left, r->left);
|
dest->left = MIN(dest->left, r->left);
|
||||||
@ -69,29 +70,15 @@ static inline void rect_union(SpiceRect *dest, const SpiceRect *r)
|
|||||||
dest->right = MAX(dest->right, r->right);
|
dest->right = MAX(dest->right, r->right);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rect_is_same_size(const SpiceRect *r1, const SpiceRect *r2)
|
static INLINE int rect_is_same_size(const SpiceRect *r1, const SpiceRect *r2)
|
||||||
{
|
{
|
||||||
return r1->right - r1->left == r2->right - r2->left &&
|
return r1->right - r1->left == r2->right - r2->left &&
|
||||||
r1->bottom - r1->top == r2->bottom - r2->top;
|
r1->bottom - r1->top == r2->bottom - r2->top;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rect_contains(const SpiceRect *big_rect, const SpiceRect *small_rect)
|
#ifdef __cplusplus
|
||||||
{
|
|
||||||
return big_rect->left <= small_rect->left && big_rect->right >= small_rect->right &&
|
|
||||||
big_rect->top <= small_rect->top && big_rect->bottom >= small_rect->bottom;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
static inline int rect_get_area(const SpiceRect *r)
|
|
||||||
{
|
|
||||||
return (r->right - r->left) * (r->bottom - r->top);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rect_debug(const SpiceRect *r)
|
|
||||||
{
|
|
||||||
spice_debug("(%d, %d) (%d, %d)", r->left, r->top, r->right, r->bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
SPICE_END_DECLS
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
@ -130,21 +117,6 @@ static inline int rect_is_same_size(const SpiceRect& r1, const SpiceRect& r2)
|
|||||||
return rect_is_same_size(&r1, &r2);
|
return rect_is_same_size(&r1, &r2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rect_contains(const SpiceRect& big_rect, const SpiceRect& small_rect)
|
#endif
|
||||||
{
|
|
||||||
return rect_contains(&big_rect, &small_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int rect_get_area(const SpiceRect& r)
|
|
||||||
{
|
|
||||||
return rect_get_area(&r);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rect_debug(const SpiceRect &r)
|
|
||||||
{
|
|
||||||
rect_debug(&r);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
394
common/region.c
394
common/region.c
@ -15,7 +15,9 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -384,17 +386,6 @@ void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void region_extents(const QRegion *rgn, SpiceRect *r)
|
|
||||||
{
|
|
||||||
pixman_box32_t *extents;
|
|
||||||
|
|
||||||
extents = pixman_region32_extents((pixman_region32_t *)rgn);
|
|
||||||
|
|
||||||
r->left = extents->x1;
|
|
||||||
r->top = extents->y1;
|
|
||||||
r->right = extents->x2;
|
|
||||||
r->bottom = extents->y2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
|
int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
|
||||||
{
|
{
|
||||||
@ -418,7 +409,7 @@ int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2)
|
|||||||
pixman_box32_t *extents1, *extents2;
|
pixman_box32_t *extents1, *extents2;
|
||||||
|
|
||||||
extents1 = pixman_region32_extents((pixman_region32_t *)rgn1);
|
extents1 = pixman_region32_extents((pixman_region32_t *)rgn1);
|
||||||
extents2 = pixman_region32_extents((pixman_region32_t *)rgn2);
|
extents2 = pixman_region32_extents((pixman_region32_t *)rgn1);
|
||||||
|
|
||||||
return EXTENTCHECK(extents1, extents2);
|
return EXTENTCHECK(extents1, extents2);
|
||||||
}
|
}
|
||||||
@ -450,7 +441,6 @@ void region_xor(QRegion *rgn, const QRegion *other_rgn)
|
|||||||
{
|
{
|
||||||
pixman_region32_t intersection;
|
pixman_region32_t intersection;
|
||||||
|
|
||||||
pixman_region32_init(&intersection);
|
|
||||||
pixman_region32_copy(&intersection, rgn);
|
pixman_region32_copy(&intersection, rgn);
|
||||||
pixman_region32_intersect(&intersection,
|
pixman_region32_intersect(&intersection,
|
||||||
&intersection,
|
&intersection,
|
||||||
@ -520,3 +510,381 @@ void region_dump(const QRegion *rgn, const char *prefix)
|
|||||||
rects[i].y2);
|
rects[i].y2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef REGION_TEST
|
||||||
|
|
||||||
|
static int slow_region_test(const QRegion *rgn, const QRegion *other_rgn, int query)
|
||||||
|
{
|
||||||
|
pixman_region32_t intersection;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
pixman_region32_init(&intersection);
|
||||||
|
pixman_region32_intersect(&intersection,
|
||||||
|
(pixman_region32_t *)rgn,
|
||||||
|
(pixman_region32_t *)other_rgn);
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
if (query & REGION_TEST_SHARED &&
|
||||||
|
pixman_region32_not_empty(&intersection)) {
|
||||||
|
res |= REGION_TEST_SHARED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query & REGION_TEST_LEFT_EXCLUSIVE &&
|
||||||
|
!pixman_region32_equal(&intersection, (pixman_region32_t *)rgn)) {
|
||||||
|
res |= REGION_TEST_LEFT_EXCLUSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query & REGION_TEST_RIGHT_EXCLUSIVE &&
|
||||||
|
!pixman_region32_equal(&intersection, (pixman_region32_t *)other_rgn)) {
|
||||||
|
res |= REGION_TEST_RIGHT_EXCLUSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_fini(&intersection);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int rect_is_valid(const SpiceRect *r)
|
||||||
|
{
|
||||||
|
if (r->top > r->bottom || r->left > r->right) {
|
||||||
|
printf("%s: invalid rect\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rect_set(SpiceRect *r, int32_t top, int32_t left, int32_t bottom, int32_t right)
|
||||||
|
{
|
||||||
|
r->top = top;
|
||||||
|
r->left = left;
|
||||||
|
r->bottom = bottom;
|
||||||
|
r->right = right;
|
||||||
|
ASSERT(rect_is_valid(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void random_region(QRegion *reg)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int num_rects;
|
||||||
|
int x, y, w, h;
|
||||||
|
SpiceRect _r;
|
||||||
|
SpiceRect *r = &_r;
|
||||||
|
|
||||||
|
region_clear(reg);
|
||||||
|
|
||||||
|
num_rects = rand() % 20;
|
||||||
|
for (i = 0; i < num_rects; i++) {
|
||||||
|
x = rand()%100;
|
||||||
|
y = rand()%100;
|
||||||
|
w = rand()%100;
|
||||||
|
h = rand()%100;
|
||||||
|
rect_set(r,
|
||||||
|
x, y,
|
||||||
|
x+w, y+h);
|
||||||
|
region_add(reg, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test(const QRegion *r1, const QRegion *r2, int *expected)
|
||||||
|
{
|
||||||
|
printf("r1 is_empty %s [%s]\n",
|
||||||
|
region_is_empty(r1) ? "TRUE" : "FALSE",
|
||||||
|
(region_is_empty(r1) == *(expected++)) ? "OK" : "ERR");
|
||||||
|
printf("r2 is_empty %s [%s]\n",
|
||||||
|
region_is_empty(r2) ? "TRUE" : "FALSE",
|
||||||
|
(region_is_empty(r2) == *(expected++)) ? "OK" : "ERR");
|
||||||
|
printf("is_equal %s [%s]\n",
|
||||||
|
region_is_equal(r1, r2) ? "TRUE" : "FALSE",
|
||||||
|
(region_is_equal(r1, r2) == *(expected++)) ? "OK" : "ERR");
|
||||||
|
printf("intersects %s [%s]\n",
|
||||||
|
region_intersects(r1, r2) ? "TRUE" : "FALSE",
|
||||||
|
(region_intersects(r1, r2) == *(expected++)) ? "OK" : "ERR");
|
||||||
|
printf("contains %s [%s]\n",
|
||||||
|
region_contains(r1, r2) ? "TRUE" : "FALSE",
|
||||||
|
(region_contains(r1, r2) == *(expected++)) ? "OK" : "ERR");
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXPECT_R1_EMPTY,
|
||||||
|
EXPECT_R2_EMPTY,
|
||||||
|
EXPECT_EQUAL,
|
||||||
|
EXPECT_SECT,
|
||||||
|
EXPECT_CONT,
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
QRegion _r1, _r2, _r3;
|
||||||
|
QRegion *r1 = &_r1;
|
||||||
|
QRegion *r2 = &_r2;
|
||||||
|
QRegion *r3 = &_r3;
|
||||||
|
SpiceRect _r;
|
||||||
|
SpiceRect *r = &_r;
|
||||||
|
int expected[5];
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
region_init(r1);
|
||||||
|
region_init(r2);
|
||||||
|
|
||||||
|
printf("dump r1 empty rgn [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r1, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_EQUAL] = TRUE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clone(r3, r1);
|
||||||
|
printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r3, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_EQUAL] = TRUE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r3, expected);
|
||||||
|
region_destroy(r3);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
rect_set(r, 0, 0, 100, 100);
|
||||||
|
region_add(r1, r);
|
||||||
|
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r1, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clear(r1);
|
||||||
|
rect_set(r, 0, 0, 0, 0);
|
||||||
|
region_add(r1, r);
|
||||||
|
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r1, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_EQUAL] = TRUE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
rect_set(r, -100, -100, 0, 0);
|
||||||
|
region_add(r1, r);
|
||||||
|
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r1, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clear(r1);
|
||||||
|
rect_set(r, -100, -100, 100, 100);
|
||||||
|
region_add(r1, r);
|
||||||
|
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r1, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
|
||||||
|
region_clear(r1);
|
||||||
|
region_clear(r2);
|
||||||
|
|
||||||
|
rect_set(r, 100, 100, 200, 200);
|
||||||
|
region_add(r1, r);
|
||||||
|
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r1, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
rect_set(r, 300, 300, 400, 400);
|
||||||
|
region_add(r1, r);
|
||||||
|
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r1, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = TRUE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
rect_set(r, 500, 500, 600, 600);
|
||||||
|
region_add(r2, r);
|
||||||
|
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r2, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = FALSE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clear(r2);
|
||||||
|
|
||||||
|
rect_set(r, 100, 100, 200, 200);
|
||||||
|
region_add(r2, r);
|
||||||
|
rect_set(r, 300, 300, 400, 400);
|
||||||
|
region_add(r2, r);
|
||||||
|
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r2, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = TRUE;
|
||||||
|
expected[EXPECT_SECT] = TRUE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clear(r2);
|
||||||
|
|
||||||
|
rect_set(r, 100, 100, 200, 200);
|
||||||
|
region_add(r2, r);
|
||||||
|
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r2, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = TRUE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clear(r2);
|
||||||
|
|
||||||
|
rect_set(r, -2000, -2000, -1000, -1000);
|
||||||
|
region_add(r2, r);
|
||||||
|
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r2, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = FALSE;
|
||||||
|
expected[EXPECT_CONT] = FALSE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clear(r2);
|
||||||
|
|
||||||
|
rect_set(r, -2000, -2000, 1000, 1000);
|
||||||
|
region_add(r2, r);
|
||||||
|
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r2, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = TRUE;
|
||||||
|
expected[EXPECT_CONT] = FALSE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clear(r2);
|
||||||
|
|
||||||
|
rect_set(r, 150, 150, 175, 175);
|
||||||
|
region_add(r2, r);
|
||||||
|
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r2, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = TRUE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_clear(r2);
|
||||||
|
|
||||||
|
rect_set(r, 150, 150, 350, 350);
|
||||||
|
region_add(r2, r);
|
||||||
|
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r2, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = TRUE;
|
||||||
|
expected[EXPECT_CONT] = FALSE;
|
||||||
|
test(r1, r2, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
region_and(r2, r1);
|
||||||
|
printf("dump r2 and r1 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r2, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = FALSE;
|
||||||
|
expected[EXPECT_SECT] = TRUE;
|
||||||
|
expected[EXPECT_CONT] = FALSE;
|
||||||
|
test(r2, r1, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
|
||||||
|
region_clone(r3, r1);
|
||||||
|
printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID");
|
||||||
|
region_dump(r3, "");
|
||||||
|
expected[EXPECT_R1_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_R2_EMPTY] = FALSE;
|
||||||
|
expected[EXPECT_EQUAL] = TRUE;
|
||||||
|
expected[EXPECT_SECT] = TRUE;
|
||||||
|
expected[EXPECT_CONT] = TRUE;
|
||||||
|
test(r1, r3, expected);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < 1000000; i++) {
|
||||||
|
int res1, res2, test;
|
||||||
|
int tests[] = {
|
||||||
|
REGION_TEST_LEFT_EXCLUSIVE,
|
||||||
|
REGION_TEST_RIGHT_EXCLUSIVE,
|
||||||
|
REGION_TEST_SHARED,
|
||||||
|
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE,
|
||||||
|
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_SHARED,
|
||||||
|
REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED,
|
||||||
|
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED
|
||||||
|
};
|
||||||
|
|
||||||
|
random_region(r1);
|
||||||
|
random_region(r2);
|
||||||
|
|
||||||
|
for (test = 0; test < 7; test++) {
|
||||||
|
res1 = region_test(r1, r2, tests[test]);
|
||||||
|
res2 = slow_region_test(r1, r2, tests[test]);
|
||||||
|
if (res1 != res2) {
|
||||||
|
printf ("Error in region_test %d, got %d, expected %d, query=%d\n",
|
||||||
|
j, res1, res2, tests[test]);
|
||||||
|
printf ("r1:\n");
|
||||||
|
region_dump(r1, "");
|
||||||
|
printf ("r2:\n");
|
||||||
|
region_dump(r2, "");
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
region_destroy(r3);
|
||||||
|
region_destroy(r1);
|
||||||
|
region_destroy(r2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -16,24 +16,21 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_REGION
|
#ifndef _H_REGION
|
||||||
#define H_SPICE_COMMON_REGION
|
#define _H_REGION
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "pixman_utils.h"
|
#include <pixman_utils.h>
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef pixman_region32_t QRegion;
|
typedef pixman_region32_t QRegion;
|
||||||
|
|
||||||
/* the left region is not contained entirely within the right region */
|
|
||||||
#define REGION_TEST_LEFT_EXCLUSIVE (1 << 0)
|
#define REGION_TEST_LEFT_EXCLUSIVE (1 << 0)
|
||||||
/* the right region is not contained entirely within the left region */
|
|
||||||
#define REGION_TEST_RIGHT_EXCLUSIVE (1 << 1)
|
#define REGION_TEST_RIGHT_EXCLUSIVE (1 << 1)
|
||||||
/* the regions overlap */
|
|
||||||
#define REGION_TEST_SHARED (1 << 2)
|
#define REGION_TEST_SHARED (1 << 2)
|
||||||
#define REGION_TEST_ALL \
|
#define REGION_TEST_ALL \
|
||||||
(REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED)
|
(REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED)
|
||||||
@ -44,7 +41,6 @@ void region_destroy(QRegion *rgn);
|
|||||||
void region_clone(QRegion *dest, const QRegion *src);
|
void region_clone(QRegion *dest, const QRegion *src);
|
||||||
SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects);
|
SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects);
|
||||||
void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects);
|
void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects);
|
||||||
void region_extents(const QRegion *rgn, SpiceRect *r);
|
|
||||||
|
|
||||||
int region_test(const QRegion *rgn, const QRegion *other_rgn, int query);
|
int region_test(const QRegion *rgn, const QRegion *other_rgn, int query);
|
||||||
int region_is_valid(const QRegion *rgn);
|
int region_is_valid(const QRegion *rgn);
|
||||||
@ -65,9 +61,10 @@ void region_remove(QRegion *rgn, const SpiceRect *r);
|
|||||||
|
|
||||||
void region_offset(QRegion *rgn, int32_t dx, int32_t dy);
|
void region_offset(QRegion *rgn, int32_t dx, int32_t dy);
|
||||||
|
|
||||||
|
|
||||||
void region_dump(const QRegion *rgn, const char *prefix);
|
void region_dump(const QRegion *rgn, const char *prefix);
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -16,12 +16,14 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_RING
|
#ifndef _H_RING2
|
||||||
#define H_SPICE_COMMON_RING
|
#define _H_RING2
|
||||||
|
|
||||||
#include "log.h"
|
#include "spice_common.h"
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct Ring RingItem;
|
typedef struct Ring RingItem;
|
||||||
typedef struct Ring {
|
typedef struct Ring {
|
||||||
@ -46,14 +48,14 @@ static inline int ring_item_is_linked(RingItem *item)
|
|||||||
|
|
||||||
static inline int ring_is_empty(Ring *ring)
|
static inline int ring_is_empty(Ring *ring)
|
||||||
{
|
{
|
||||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||||
return ring == ring->next;
|
return ring == ring->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ring_add(Ring *ring, RingItem *item)
|
static inline void ring_add(Ring *ring, RingItem *item)
|
||||||
{
|
{
|
||||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||||
spice_assert(item->next == NULL && item->prev == NULL);
|
ASSERT(item->next == NULL && item->prev == NULL);
|
||||||
|
|
||||||
item->next = ring->next;
|
item->next = ring->next;
|
||||||
item->prev = ring;
|
item->prev = ring;
|
||||||
@ -70,43 +72,54 @@ static inline void ring_add_before(RingItem *item, RingItem *pos)
|
|||||||
ring_add(pos->prev, item);
|
ring_add(pos->prev, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ring_remove(RingItem *item)
|
static inline void __ring_remove(RingItem *item)
|
||||||
{
|
{
|
||||||
spice_assert(item->next != NULL && item->prev != NULL);
|
|
||||||
spice_assert(item->next != item);
|
|
||||||
|
|
||||||
item->next->prev = item->prev;
|
item->next->prev = item->prev;
|
||||||
item->prev->next = item->next;
|
item->prev->next = item->next;
|
||||||
item->prev = item->next = NULL;
|
item->prev = item->next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ring_remove(RingItem *item)
|
||||||
|
{
|
||||||
|
ASSERT(item->next != NULL && item->prev != NULL);
|
||||||
|
ASSERT(item->next != item);
|
||||||
|
|
||||||
|
__ring_remove(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline RingItem *ring_get_head(Ring *ring)
|
static inline RingItem *ring_get_head(Ring *ring)
|
||||||
{
|
{
|
||||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
RingItem *ret;
|
||||||
|
|
||||||
|
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||||
|
|
||||||
if (ring_is_empty(ring)) {
|
if (ring_is_empty(ring)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return ring->next;
|
ret = ring->next;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline RingItem *ring_get_tail(Ring *ring)
|
static inline RingItem *ring_get_tail(Ring *ring)
|
||||||
{
|
{
|
||||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
RingItem *ret;
|
||||||
|
|
||||||
|
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||||
|
|
||||||
if (ring_is_empty(ring)) {
|
if (ring_is_empty(ring)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return ring->prev;
|
ret = ring->prev;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline RingItem *ring_next(Ring *ring, RingItem *pos)
|
static inline RingItem *ring_next(Ring *ring, RingItem *pos)
|
||||||
{
|
{
|
||||||
RingItem *ret;
|
RingItem *ret;
|
||||||
|
|
||||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||||
spice_assert(pos);
|
ASSERT(pos);
|
||||||
spice_assert(pos->next != NULL && pos->prev != NULL);
|
ASSERT(pos->next != NULL && pos->prev != NULL);
|
||||||
ret = pos->next;
|
ret = pos->next;
|
||||||
return (ret == ring) ? NULL : ret;
|
return (ret == ring) ? NULL : ret;
|
||||||
}
|
}
|
||||||
@ -115,9 +128,9 @@ static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
|
|||||||
{
|
{
|
||||||
RingItem *ret;
|
RingItem *ret;
|
||||||
|
|
||||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||||
spice_assert(pos);
|
ASSERT(pos);
|
||||||
spice_assert(pos->next != NULL && pos->prev != NULL);
|
ASSERT(pos->next != NULL && pos->prev != NULL);
|
||||||
ret = pos->prev;
|
ret = pos->prev;
|
||||||
return (ret == ring) ? NULL : ret;
|
return (ret == ring) ? NULL : ret;
|
||||||
}
|
}
|
||||||
@ -144,12 +157,16 @@ static inline unsigned int ring_get_length(Ring *ring)
|
|||||||
RingItem *i;
|
RingItem *i;
|
||||||
unsigned int ret = 0;
|
unsigned int ret = 0;
|
||||||
|
|
||||||
RING_FOREACH(i, ring)
|
for (i = ring_get_head(ring);
|
||||||
|
i != NULL;
|
||||||
|
i = ring_next(ring, i))
|
||||||
ret++;
|
ret++;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -15,9 +15,14 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "rop3.h"
|
#include "rop3.h"
|
||||||
|
#include "spice_common.h"
|
||||||
|
|
||||||
typedef void (*rop3_with_pattern_handler_t)(pixman_image_t *d, pixman_image_t *s,
|
typedef void (*rop3_with_pattern_handler_t)(pixman_image_t *d, pixman_image_t *s,
|
||||||
SpicePoint *src_pos, pixman_image_t *p,
|
SpicePoint *src_pos, pixman_image_t *p,
|
||||||
@ -38,21 +43,17 @@ static rop3_test_handler_t rop3_test_handlers_32[ROP3_NUM_OPS];
|
|||||||
static rop3_test_handler_t rop3_test_handlers_16[ROP3_NUM_OPS];
|
static rop3_test_handler_t rop3_test_handlers_16[ROP3_NUM_OPS];
|
||||||
|
|
||||||
|
|
||||||
static void default_rop3_with_pattern_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
|
static void default_rop3_with_pattern_handler(pixman_image_t *d, pixman_image_t *s,
|
||||||
SPICE_GNUC_UNUSED pixman_image_t *s,
|
SpicePoint *src_pos, pixman_image_t *p,
|
||||||
SPICE_GNUC_UNUSED SpicePoint *src_pos,
|
SpicePoint *pat_pos)
|
||||||
SPICE_GNUC_UNUSED pixman_image_t *p,
|
|
||||||
SPICE_GNUC_UNUSED SpicePoint *pat_pos)
|
|
||||||
{
|
{
|
||||||
spice_critical("not implemented");
|
WARN("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_rop3_withe_color_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
|
static void default_rop3_withe_color_handler(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
||||||
SPICE_GNUC_UNUSED pixman_image_t *s,
|
uint32_t rgb)
|
||||||
SPICE_GNUC_UNUSED SpicePoint *src_pos,
|
|
||||||
SPICE_GNUC_UNUSED uint32_t rgb)
|
|
||||||
{
|
{
|
||||||
spice_critical("not implemented");
|
WARN("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_rop3_test_handler(void)
|
static void default_rop3_test_handler(void)
|
||||||
@ -373,10 +374,16 @@ ROP3_HANDLERS(DPSoo, *src | *pat | *dest, 0xfe);
|
|||||||
rop3_test_handlers_32[index] = rop3_test32_##op; \
|
rop3_test_handlers_32[index] = rop3_test32_##op; \
|
||||||
rop3_test_handlers_16[index] = rop3_test16_##op;
|
rop3_test_handlers_16[index] = rop3_test16_##op;
|
||||||
|
|
||||||
SPICE_CONSTRUCTOR_FUNC(rop3_global_init)
|
void rop3_init(void)
|
||||||
{
|
{
|
||||||
|
static int need_init = 1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!need_init) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
need_init = 0;
|
||||||
|
|
||||||
for (i = 0; i < ROP3_NUM_OPS; i++) {
|
for (i = 0; i < ROP3_NUM_OPS; i++) {
|
||||||
rop3_with_pattern_handlers_32[i] = default_rop3_with_pattern_handler;
|
rop3_with_pattern_handlers_32[i] = default_rop3_with_pattern_handler;
|
||||||
rop3_with_pattern_handlers_16[i] = default_rop3_with_pattern_handler;
|
rop3_with_pattern_handlers_16[i] = default_rop3_with_pattern_handler;
|
||||||
@ -617,8 +624,8 @@ void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, Sp
|
|||||||
int bpp;
|
int bpp;
|
||||||
|
|
||||||
bpp = spice_pixman_image_get_bpp(d);
|
bpp = spice_pixman_image_get_bpp(d);
|
||||||
spice_assert(bpp == spice_pixman_image_get_bpp(s));
|
ASSERT (bpp == spice_pixman_image_get_bpp(s));
|
||||||
spice_assert(bpp == spice_pixman_image_get_bpp(p));
|
ASSERT (bpp == spice_pixman_image_get_bpp(p));
|
||||||
|
|
||||||
if (bpp == 32) {
|
if (bpp == 32) {
|
||||||
rop3_with_pattern_handlers_32[rop3](d, s, src_pos, p, pat_pos);
|
rop3_with_pattern_handlers_32[rop3](d, s, src_pos, p, pat_pos);
|
||||||
@ -633,7 +640,7 @@ void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, Spic
|
|||||||
int bpp;
|
int bpp;
|
||||||
|
|
||||||
bpp = spice_pixman_image_get_bpp(d);
|
bpp = spice_pixman_image_get_bpp(d);
|
||||||
spice_assert(bpp == spice_pixman_image_get_bpp(s));
|
ASSERT (bpp == spice_pixman_image_get_bpp(s));
|
||||||
|
|
||||||
if (bpp == 32) {
|
if (bpp == 32) {
|
||||||
rop3_with_color_handlers_32[rop3](d, s, src_pos, rgb);
|
rop3_with_color_handlers_32[rop3](d, s, src_pos, rgb);
|
||||||
|
|||||||
@ -16,22 +16,27 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_ROP3
|
#ifndef _H_ROP3
|
||||||
#define H_SPICE_COMMON_ROP3
|
#define _H_ROP3
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
||||||
pixman_image_t *p, SpicePoint *pat_pos);
|
pixman_image_t *p, SpicePoint *pat_pos);
|
||||||
void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
||||||
uint32_t rgb);
|
uint32_t rgb);
|
||||||
|
|
||||||
SPICE_END_DECLS
|
void rop3_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,276 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2013 Jeremy White
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* snd_codec.c
|
|
||||||
General purpose sound codec routines for use by Spice.
|
|
||||||
These routines abstract the work of picking a codec and
|
|
||||||
encoding and decoding the buffers.
|
|
||||||
|
|
||||||
See below for documentation of the public routines.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if HAVE_OPUS
|
|
||||||
#include <opus.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <spice/macros.h>
|
|
||||||
#include <spice/enums.h>
|
|
||||||
|
|
||||||
#include "snd_codec.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
typedef struct SndCodecInternal
|
|
||||||
{
|
|
||||||
SpiceAudioDataMode mode;
|
|
||||||
int frequency;
|
|
||||||
|
|
||||||
#if HAVE_OPUS
|
|
||||||
OpusEncoder *opus_encoder;
|
|
||||||
OpusDecoder *opus_decoder;
|
|
||||||
#endif
|
|
||||||
} SndCodecInternal;
|
|
||||||
|
|
||||||
|
|
||||||
/* Opus support routines */
|
|
||||||
#if HAVE_OPUS
|
|
||||||
static void snd_codec_destroy_opus(SndCodecInternal *codec)
|
|
||||||
{
|
|
||||||
if (codec->opus_decoder) {
|
|
||||||
opus_decoder_destroy(codec->opus_decoder);
|
|
||||||
codec->opus_decoder = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (codec->opus_encoder) {
|
|
||||||
opus_encoder_destroy(codec->opus_encoder);
|
|
||||||
codec->opus_encoder = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static SndCodecResult snd_codec_create_opus(SndCodecInternal *codec, int purpose)
|
|
||||||
{
|
|
||||||
int opus_error;
|
|
||||||
|
|
||||||
if (purpose & SND_CODEC_ENCODE) {
|
|
||||||
codec->opus_encoder = opus_encoder_create(codec->frequency,
|
|
||||||
SND_CODEC_PLAYBACK_CHAN,
|
|
||||||
OPUS_APPLICATION_AUDIO, &opus_error);
|
|
||||||
if (! codec->opus_encoder) {
|
|
||||||
g_warning("create opus encoder failed; error %d", opus_error);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (purpose & SND_CODEC_DECODE) {
|
|
||||||
codec->opus_decoder = opus_decoder_create(codec->frequency,
|
|
||||||
SND_CODEC_PLAYBACK_CHAN, &opus_error);
|
|
||||||
if (! codec->opus_decoder) {
|
|
||||||
g_warning("create opus decoder failed; error %d", opus_error);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
codec->mode = SPICE_AUDIO_DATA_MODE_OPUS;
|
|
||||||
return SND_CODEC_OK;
|
|
||||||
|
|
||||||
error:
|
|
||||||
snd_codec_destroy_opus(codec);
|
|
||||||
return SND_CODEC_UNAVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SndCodecResult
|
|
||||||
snd_codec_encode_opus(SndCodecInternal *codec, uint8_t *in_ptr, int in_size,
|
|
||||||
uint8_t *out_ptr, int *out_size)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
if (in_size != SND_CODEC_OPUS_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2)
|
|
||||||
return SND_CODEC_INVALID_ENCODE_SIZE;
|
|
||||||
n = opus_encode(codec->opus_encoder, (opus_int16 *) in_ptr, SND_CODEC_OPUS_FRAME_SIZE, out_ptr, *out_size);
|
|
||||||
if (n < 0) {
|
|
||||||
g_warning("opus_encode failed %d", n);
|
|
||||||
return SND_CODEC_ENCODE_FAILED;
|
|
||||||
}
|
|
||||||
*out_size = n;
|
|
||||||
return SND_CODEC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SndCodecResult
|
|
||||||
snd_codec_decode_opus(SndCodecInternal *codec, uint8_t *in_ptr, int in_size,
|
|
||||||
uint8_t *out_ptr, int *out_size)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
n = opus_decode(codec->opus_decoder, in_ptr, in_size, (opus_int16 *) out_ptr,
|
|
||||||
*out_size / SND_CODEC_PLAYBACK_CHAN / 2, 0);
|
|
||||||
if (n < 0) {
|
|
||||||
g_warning("opus_decode failed %d", n);
|
|
||||||
return SND_CODEC_DECODE_FAILED;
|
|
||||||
}
|
|
||||||
*out_size = n * SND_CODEC_PLAYBACK_CHAN * 2 /* 16 fmt */;
|
|
||||||
return SND_CODEC_OK;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
|
||||||
** PUBLIC INTERFACE
|
|
||||||
**--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
snd_codec_is_capable
|
|
||||||
Returns true if the current spice implementation can
|
|
||||||
use the given codec, false otherwise.
|
|
||||||
mode must be a SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h
|
|
||||||
*/
|
|
||||||
bool snd_codec_is_capable(SpiceAudioDataMode mode, int frequency)
|
|
||||||
{
|
|
||||||
#if HAVE_OPUS
|
|
||||||
if (mode == SPICE_AUDIO_DATA_MODE_OPUS &&
|
|
||||||
(frequency == SND_CODEC_ANY_FREQUENCY ||
|
|
||||||
frequency == 48000 || frequency == 24000 ||
|
|
||||||
frequency == 16000 || frequency == 12000 ||
|
|
||||||
frequency == 8000) )
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
snd_codec_create
|
|
||||||
Create a codec control. Required for most functions in this library.
|
|
||||||
Parameters:
|
|
||||||
1. codec Pointer to preallocated codec control
|
|
||||||
2. mode SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h
|
|
||||||
3. encode TRUE if encoding is desired
|
|
||||||
4. decode TRUE if decoding is desired
|
|
||||||
Returns:
|
|
||||||
SND_CODEC_OK if all went well; a different code if not.
|
|
||||||
|
|
||||||
snd_codec_destroy is the obvious partner of snd_codec_create.
|
|
||||||
*/
|
|
||||||
SndCodecResult
|
|
||||||
snd_codec_create(SndCodec *codec, SpiceAudioDataMode mode, int frequency, int purpose)
|
|
||||||
{
|
|
||||||
SndCodecResult rc = SND_CODEC_UNAVAILABLE;
|
|
||||||
SndCodecInternal **c = codec;
|
|
||||||
|
|
||||||
*c = spice_new0(SndCodecInternal, 1);
|
|
||||||
(*c)->frequency = frequency;
|
|
||||||
|
|
||||||
#if HAVE_OPUS
|
|
||||||
if (mode == SPICE_AUDIO_DATA_MODE_OPUS)
|
|
||||||
rc = snd_codec_create_opus(*c, purpose);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
snd_codec_destroy
|
|
||||||
The obvious companion to snd_codec_create
|
|
||||||
*/
|
|
||||||
void snd_codec_destroy(SndCodec *codec)
|
|
||||||
{
|
|
||||||
SndCodecInternal **c = codec;
|
|
||||||
if (! c || ! *c)
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if HAVE_OPUS
|
|
||||||
snd_codec_destroy_opus(*c);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
free(*c);
|
|
||||||
*c = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
snd_codec_frame_size
|
|
||||||
Returns the size, in frames, of the raw PCM frame buffer
|
|
||||||
required by this codec. To get bytes, you'll need
|
|
||||||
to multiply by channels and sample width.
|
|
||||||
*/
|
|
||||||
int snd_codec_frame_size(SndCodec codec)
|
|
||||||
{
|
|
||||||
#if HAVE_OPUS
|
|
||||||
SndCodecInternal *c = codec;
|
|
||||||
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
|
|
||||||
return SND_CODEC_OPUS_FRAME_SIZE;
|
|
||||||
#endif
|
|
||||||
return SND_CODEC_MAX_FRAME_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
snd_codec_encode
|
|
||||||
Encode a block of data to a compressed buffer.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
1. codec Pointer to codec control previously allocated + created
|
|
||||||
2. in_ptr Pointer to uncompressed PCM data
|
|
||||||
3. in_size Input size
|
|
||||||
4. out_ptr Pointer to area to write encoded data
|
|
||||||
5. out_size On input, the maximum size of the output buffer; on
|
|
||||||
successful return, it will hold the number of bytes
|
|
||||||
returned.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
SND_CODEC_OK if all went well
|
|
||||||
*/
|
|
||||||
SndCodecResult
|
|
||||||
snd_codec_encode(SndCodec codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
|
|
||||||
{
|
|
||||||
#if HAVE_OPUS
|
|
||||||
SndCodecInternal *c = codec;
|
|
||||||
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
|
|
||||||
return snd_codec_encode_opus(c, in_ptr, in_size, out_ptr, out_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return SND_CODEC_ENCODER_UNAVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
snd_codec_decode
|
|
||||||
Decode a block of data from a compressed buffer.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
1. codec Pointer to codec control previously allocated + created
|
|
||||||
2. in_ptr Pointer to compressed data
|
|
||||||
3. in_size Input size
|
|
||||||
4. out_ptr Pointer to area to write decoded data
|
|
||||||
5. out_size On input, the maximum size of the output buffer; on
|
|
||||||
successful return, it will hold the number of bytes
|
|
||||||
returned.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
SND_CODEC_OK if all went well
|
|
||||||
*/
|
|
||||||
SndCodecResult
|
|
||||||
snd_codec_decode(SndCodec codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
|
|
||||||
{
|
|
||||||
#if HAVE_OPUS
|
|
||||||
SndCodecInternal *c = codec;
|
|
||||||
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
|
|
||||||
return snd_codec_decode_opus(c, in_ptr, in_size, out_ptr, out_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return SND_CODEC_DECODER_UNAVAILABLE;
|
|
||||||
}
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2013 Jeremy White <jwhite@codeweavers.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_SND_CODEC
|
|
||||||
#define H_SPICE_COMMON_SND_CODEC
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <spice/enums.h>
|
|
||||||
|
|
||||||
#define SND_CODEC_OPUS_FRAME_SIZE 480
|
|
||||||
#define SND_CODEC_OPUS_PLAYBACK_FREQ 48000
|
|
||||||
#define SND_CODEC_OPUS_COMPRESSED_FRAME_BYTES 480
|
|
||||||
|
|
||||||
#define SND_CODEC_PLAYBACK_CHAN 2
|
|
||||||
|
|
||||||
#define SND_CODEC_MAX_FRAME_SIZE SND_CODEC_OPUS_FRAME_SIZE
|
|
||||||
#define SND_CODEC_MAX_FRAME_BYTES (SND_CODEC_MAX_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2 /* FMT_S16 */)
|
|
||||||
#define SND_CODEC_MAX_COMPRESSED_BYTES SND_CODEC_OPUS_COMPRESSED_FRAME_BYTES
|
|
||||||
|
|
||||||
#define SND_CODEC_ANY_FREQUENCY -1
|
|
||||||
|
|
||||||
#define SND_CODEC_ENCODE 0x0001
|
|
||||||
#define SND_CODEC_DECODE 0x0002
|
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SND_CODEC_OK,
|
|
||||||
SND_CODEC_UNAVAILABLE,
|
|
||||||
SND_CODEC_ENCODER_UNAVAILABLE,
|
|
||||||
SND_CODEC_DECODER_UNAVAILABLE,
|
|
||||||
SND_CODEC_ENCODE_FAILED,
|
|
||||||
SND_CODEC_DECODE_FAILED,
|
|
||||||
SND_CODEC_INVALID_ENCODE_SIZE,
|
|
||||||
} SndCodecResult;
|
|
||||||
|
|
||||||
typedef struct SndCodecInternal * SndCodec;
|
|
||||||
|
|
||||||
bool snd_codec_is_capable(SpiceAudioDataMode mode, int frequency);
|
|
||||||
|
|
||||||
SndCodecResult snd_codec_create(SndCodec *codec,
|
|
||||||
SpiceAudioDataMode mode, int frequency, int purpose);
|
|
||||||
void snd_codec_destroy(SndCodec *codec);
|
|
||||||
|
|
||||||
int snd_codec_frame_size(SndCodec codec);
|
|
||||||
|
|
||||||
SndCodecResult snd_codec_encode(SndCodec codec, uint8_t *in_ptr, int in_size,
|
|
||||||
uint8_t *out_ptr, int *out_size);
|
|
||||||
SndCodecResult snd_codec_decode(SndCodec codec, uint8_t *in_ptr, int in_size,
|
|
||||||
uint8_t *out_ptr, int *out_size);
|
|
||||||
|
|
||||||
SPICE_END_DECLS
|
|
||||||
|
|
||||||
#endif
|
|
||||||
78
common/spice_common.h
Normal file
78
common/spice_common.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_SPICE_COMMON
|
||||||
|
#define H_SPICE_COMMON
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "backtrace.h"
|
||||||
|
|
||||||
|
#define ASSERT(x) if (!(x)) { \
|
||||||
|
printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \
|
||||||
|
spice_backtrace(); \
|
||||||
|
abort(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PANIC(format, ...) do { \
|
||||||
|
printf("%s: panic: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
|
||||||
|
abort(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define PANIC_ON(x) if ((x)) { \
|
||||||
|
printf("%s: panic %s\n", __FUNCTION__, #x); \
|
||||||
|
abort(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define red_error(format, ...) do { \
|
||||||
|
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
|
||||||
|
abort(); \
|
||||||
|
} while (0)
|
||||||
|
#define red_printf(format, ...) \
|
||||||
|
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define red_printf_once(format, ...) do { \
|
||||||
|
static int do_print = TRUE; \
|
||||||
|
if (do_print) { \
|
||||||
|
do_print = FALSE; \
|
||||||
|
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define WARN(format, ...) red_printf("warning: "format, ##__VA_ARGS__ );
|
||||||
|
#define WARN_ONCE red_printf_once
|
||||||
|
|
||||||
|
#define red_printf_some(every, format, ...) do { \
|
||||||
|
static int count = 0; \
|
||||||
|
if (count++ % (every) == 0) { \
|
||||||
|
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define red_printf_debug(debug, prefix, format, ...) do { \
|
||||||
|
static int debug_level = -1; \
|
||||||
|
if (debug_level == -1) { \
|
||||||
|
debug_level = getenv("SPICE_DEBUG_LEVEL") != NULL ? atoi(getenv("SPICE_DEBUG_LEVEL")) : 0; \
|
||||||
|
} \
|
||||||
|
if (debug <= debug_level) { \
|
||||||
|
printf("%s: %s: " format "\n", prefix, __FUNCTION__, ## __VA_ARGS__ ); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -16,11 +16,12 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "ssl_verify.h"
|
#include "ssl_verify.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@ -28,14 +29,21 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
|
||||||
#include <gio/gio.h>
|
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
|
#ifndef SPICE_DEBUG
|
||||||
(defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000)
|
# define SPICE_DEBUG(format, ...)
|
||||||
static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1)
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
static int inet_aton(const char* ip, struct in_addr* in_addr)
|
||||||
{
|
{
|
||||||
return M_ASN1_STRING_data(asn1);
|
unsigned long addr = inet_addr(ip);
|
||||||
|
|
||||||
|
if (addr == INADDR_NONE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
in_addr->S_un.S_addr = addr;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -50,41 +58,36 @@ static int verify_pubkey(X509* cert, const char *key, size_t key_size)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
spice_debug("warning: no cert!");
|
SPICE_DEBUG("warning: no cert!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cert_pubkey = X509_get_pubkey(cert);
|
cert_pubkey = X509_get_pubkey(cert);
|
||||||
if (!cert_pubkey) {
|
if (!cert_pubkey) {
|
||||||
spice_debug("warning: reading public key from certificate failed");
|
SPICE_DEBUG("warning: reading public key from certificate failed");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
bio = BIO_new_mem_buf((void*)key, key_size);
|
bio = BIO_new_mem_buf((void*)key, key_size);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
spice_debug("creating BIO failed");
|
SPICE_DEBUG("creating BIO failed");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
orig_pubkey = d2i_PUBKEY_bio(bio, NULL);
|
orig_pubkey = d2i_PUBKEY_bio(bio, NULL);
|
||||||
if (!orig_pubkey) {
|
if (!orig_pubkey) {
|
||||||
spice_debug("reading pubkey from bio failed");
|
SPICE_DEBUG("reading pubkey from bio failed");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
||||||
ret = EVP_PKEY_eq(orig_pubkey, cert_pubkey);
|
|
||||||
#else
|
|
||||||
ret = EVP_PKEY_cmp(orig_pubkey, cert_pubkey);
|
ret = EVP_PKEY_cmp(orig_pubkey, cert_pubkey);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ret == 1) {
|
if (ret == 1)
|
||||||
spice_debug("public keys match");
|
SPICE_DEBUG("public keys match");
|
||||||
} else if (ret == 0) {
|
else if (ret == 0)
|
||||||
spice_debug("public keys mismatch");
|
SPICE_DEBUG("public keys mismatch");
|
||||||
} else {
|
else
|
||||||
spice_debug("public keys types mismatch");
|
SPICE_DEBUG("public keys types mismatch");
|
||||||
}
|
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (bio)
|
if (bio)
|
||||||
@ -159,16 +162,21 @@ static int verify_hostname(X509* cert, const char *hostname)
|
|||||||
{
|
{
|
||||||
GENERAL_NAMES* subject_alt_names;
|
GENERAL_NAMES* subject_alt_names;
|
||||||
int found_dns_name = 0;
|
int found_dns_name = 0;
|
||||||
|
struct in_addr addr;
|
||||||
|
int addr_len = 0;
|
||||||
int cn_match = 0;
|
int cn_match = 0;
|
||||||
X509_NAME* subject;
|
X509_NAME* subject;
|
||||||
|
|
||||||
spice_return_val_if_fail(hostname != NULL, 0);
|
|
||||||
|
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
spice_debug("warning: no cert!");
|
SPICE_DEBUG("warning: no cert!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only IpV4 supported
|
||||||
|
if (inet_aton(hostname, &addr)) {
|
||||||
|
addr_len = sizeof(struct in_addr);
|
||||||
|
}
|
||||||
|
|
||||||
/* try matching against:
|
/* try matching against:
|
||||||
* 1) a DNS name as an alternative name (subjectAltName) extension
|
* 1) a DNS name as an alternative name (subjectAltName) extension
|
||||||
* in the certificate
|
* in the certificate
|
||||||
@ -192,56 +200,30 @@ static int verify_hostname(X509* cert, const char *hostname)
|
|||||||
const GENERAL_NAME* name = sk_GENERAL_NAME_value(subject_alt_names, i);
|
const GENERAL_NAME* name = sk_GENERAL_NAME_value(subject_alt_names, i);
|
||||||
if (name->type == GEN_DNS) {
|
if (name->type == GEN_DNS) {
|
||||||
found_dns_name = 1;
|
found_dns_name = 1;
|
||||||
if (_gnutls_hostname_compare((const char *)ASN1_STRING_get0_data(name->d.dNSName),
|
if (_gnutls_hostname_compare((char *)ASN1_STRING_data(name->d.dNSName),
|
||||||
ASN1_STRING_length(name->d.dNSName),
|
ASN1_STRING_length(name->d.dNSName),
|
||||||
hostname)) {
|
hostname)) {
|
||||||
spice_debug("alt name match=%s", ASN1_STRING_get0_data(name->d.dNSName));
|
SPICE_DEBUG("alt name match=%s", ASN1_STRING_data(name->d.dNSName));
|
||||||
GENERAL_NAMES_free(subject_alt_names);
|
GENERAL_NAMES_free(subject_alt_names);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else if (name->type == GEN_IPADD) {
|
} else if (name->type == GEN_IPADD) {
|
||||||
GInetAddress * ip;
|
int alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
|
||||||
const guint8 * ip_binary;
|
|
||||||
int alt_ip_len;
|
|
||||||
int ip_len;
|
|
||||||
|
|
||||||
found_dns_name = 1;
|
found_dns_name = 1;
|
||||||
|
if ((addr_len == alt_ip_len)&&
|
||||||
ip = g_inet_address_new_from_string(hostname);
|
!memcmp(ASN1_STRING_data(name->d.iPAddress), &addr, addr_len)) {
|
||||||
if (ip == NULL) {
|
SPICE_DEBUG("alt name IP match=%s",
|
||||||
spice_warning("Could not parse hostname: %s", hostname);
|
inet_ntoa(*((struct in_addr*)ASN1_STRING_data(name->d.dNSName))));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ip_len = g_inet_address_get_native_size(ip);
|
|
||||||
ip_binary = g_inet_address_to_bytes(ip);
|
|
||||||
|
|
||||||
alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
|
|
||||||
|
|
||||||
if ((ip_len == alt_ip_len) &&
|
|
||||||
(memcmp(ASN1_STRING_get0_data(name->d.iPAddress), ip_binary, ip_len)) == 0) {
|
|
||||||
GInetAddress * alt_ip = NULL;
|
|
||||||
gchar * alt_ip_string = NULL;
|
|
||||||
|
|
||||||
alt_ip = g_inet_address_new_from_bytes(ASN1_STRING_get0_data(name->d.iPAddress),
|
|
||||||
g_inet_address_get_family(ip));
|
|
||||||
alt_ip_string = g_inet_address_to_string(alt_ip);
|
|
||||||
spice_debug("alt name IP match=%s", alt_ip_string);
|
|
||||||
|
|
||||||
g_free(alt_ip_string);
|
|
||||||
g_object_unref(alt_ip);
|
|
||||||
g_object_unref(ip);
|
|
||||||
GENERAL_NAMES_free(subject_alt_names);
|
GENERAL_NAMES_free(subject_alt_names);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
g_object_unref(ip);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GENERAL_NAMES_free(subject_alt_names);
|
GENERAL_NAMES_free(subject_alt_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_dns_name) {
|
if (found_dns_name) {
|
||||||
spice_debug("warning: SubjectAltName mismatch");
|
SPICE_DEBUG("warning: SubjectAltName mismatch");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,41 +244,38 @@ static int verify_hostname(X509* cert, const char *hostname)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_gnutls_hostname_compare((const char*)ASN1_STRING_get0_data(cn_asn1),
|
if (_gnutls_hostname_compare((char*)ASN1_STRING_data(cn_asn1),
|
||||||
ASN1_STRING_length(cn_asn1),
|
ASN1_STRING_length(cn_asn1),
|
||||||
hostname)) {
|
hostname)) {
|
||||||
spice_debug("common name match=%s", (char*)ASN1_STRING_get0_data(cn_asn1));
|
SPICE_DEBUG("common name match=%s", (char*)ASN1_STRING_data(cn_asn1));
|
||||||
cn_match = 1;
|
cn_match = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cn_match) {
|
if (!cn_match)
|
||||||
spice_debug("warning: common name mismatch");
|
SPICE_DEBUG("warning: common name mismatch");
|
||||||
}
|
|
||||||
|
|
||||||
return cn_match;
|
return cn_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
static X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
||||||
{
|
{
|
||||||
X509_NAME* in_subject;
|
X509_NAME* in_subject;
|
||||||
const char *p;
|
const char *p;
|
||||||
char *key, *val = NULL, *k, *v = NULL;
|
char *key, *val, *k, *v = NULL;
|
||||||
enum {
|
enum {
|
||||||
KEY,
|
KEY,
|
||||||
VALUE
|
VALUE
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
spice_return_val_if_fail(subject != NULL, NULL);
|
key = (char*)alloca(strlen(subject));
|
||||||
spice_return_val_if_fail(nentries != NULL, NULL);
|
val = (char*)alloca(strlen(subject));
|
||||||
|
|
||||||
key = (char*)alloca(strlen(subject)+1);
|
|
||||||
in_subject = X509_NAME_new();
|
in_subject = X509_NAME_new();
|
||||||
|
|
||||||
if (!in_subject || !key) {
|
if (!in_subject || !key || !val) {
|
||||||
spice_debug("failed to allocate");
|
SPICE_DEBUG("failed to allocate");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +288,7 @@ static X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
|||||||
if (*p == '\\') {
|
if (*p == '\\') {
|
||||||
++p;
|
++p;
|
||||||
if (*p != '\\' && *p != ',') {
|
if (*p != '\\' && *p != ',') {
|
||||||
spice_debug("Invalid character after \\");
|
SPICE_DEBUG("Invalid character after \\");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
escape = 1;
|
escape = 1;
|
||||||
@ -328,7 +307,6 @@ static X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
|||||||
} else if (*p == '=' && !escape) {
|
} else if (*p == '=' && !escape) {
|
||||||
state = VALUE;
|
state = VALUE;
|
||||||
*k = 0;
|
*k = 0;
|
||||||
val = k + 1;
|
|
||||||
v = val;
|
v = val;
|
||||||
} else
|
} else
|
||||||
*k++ = *p;
|
*k++ = *p;
|
||||||
@ -344,7 +322,7 @@ static X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
|||||||
MBSTRING_UTF8,
|
MBSTRING_UTF8,
|
||||||
(const unsigned char*)val,
|
(const unsigned char*)val,
|
||||||
-1, -1, 0)) {
|
-1, -1, 0)) {
|
||||||
spice_debug("warning: failed to add entry %s=%s to X509_NAME",
|
SPICE_DEBUG("warning: failed to add entry %s=%s to X509_NAME",
|
||||||
key, val);
|
key, val);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -371,145 +349,89 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
|
int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
|
||||||
{
|
{
|
||||||
X509_NAME *cert_subject = NULL;
|
X509_NAME *cert_subject = NULL;
|
||||||
X509_NAME* in_subject;
|
|
||||||
int ret;
|
int ret;
|
||||||
int in_entries;
|
int in_entries;
|
||||||
|
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
spice_debug("warning: no cert!");
|
SPICE_DEBUG("warning: no cert!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cert_subject = X509_get_subject_name(cert);
|
cert_subject = X509_get_subject_name(cert);
|
||||||
if (!cert_subject) {
|
if (!cert_subject) {
|
||||||
spice_debug("warning: reading certificate subject failed");
|
SPICE_DEBUG("warning: reading certificate subject failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_subject = subject_to_x509_name(verify->subject, &in_entries);
|
if (!verify->in_subject) {
|
||||||
if (!in_subject) {
|
verify->in_subject = subject_to_x509_name(verify->subject, &in_entries);
|
||||||
spice_debug("warning: no in_subject!");
|
if (!verify->in_subject) {
|
||||||
return 0;
|
SPICE_DEBUG("warning: no in_subject!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: this check is redundant with the pre-condition in X509_NAME_cmp */
|
/* Note: this check is redundant with the pre-condition in X509_NAME_cmp */
|
||||||
if (X509_NAME_entry_count(cert_subject) != in_entries) {
|
if (X509_NAME_entry_count(cert_subject) != in_entries) {
|
||||||
spice_debug("subject mismatch: #entries cert=%d, input=%d",
|
SPICE_DEBUG("subject mismatch: #entries cert=%d, input=%d",
|
||||||
X509_NAME_entry_count(cert_subject), in_entries);
|
X509_NAME_entry_count(cert_subject), in_entries);
|
||||||
X509_NAME_free(in_subject);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = X509_NAME_cmp(cert_subject, in_subject);
|
ret = X509_NAME_cmp(cert_subject, verify->in_subject);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0)
|
||||||
spice_debug("subjects match");
|
SPICE_DEBUG("subjects match");
|
||||||
} else {
|
else
|
||||||
char *p;
|
SPICE_DEBUG("subjects mismatch");
|
||||||
spice_debug("subjects mismatch");
|
|
||||||
|
|
||||||
p = X509_NAME_oneline(cert_subject, NULL, 0);
|
|
||||||
spice_debug("cert_subject: %s", p);
|
|
||||||
free(p);
|
|
||||||
|
|
||||||
p = X509_NAME_oneline(in_subject, NULL, 0);
|
|
||||||
spice_debug("in_subject: %s", p);
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
X509_NAME_free(in_subject);
|
|
||||||
|
|
||||||
return !ret;
|
return !ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openssl_verify(int preverify_ok, X509_STORE_CTX *ctx)
|
static int openssl_verify(int preverify_ok, X509_STORE_CTX *ctx)
|
||||||
{
|
{
|
||||||
int depth, err;
|
int depth;
|
||||||
SpiceOpenSSLVerify *v;
|
SpiceOpenSSLVerify *v;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
X509* cert;
|
X509* cert;
|
||||||
char buf[256];
|
|
||||||
unsigned int failed_verifications;
|
|
||||||
|
|
||||||
ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||||
v = (SpiceOpenSSLVerify*)SSL_get_app_data(ssl);
|
v = (SpiceOpenSSLVerify*)SSL_get_app_data(ssl);
|
||||||
|
|
||||||
cert = X509_STORE_CTX_get_current_cert(ctx);
|
|
||||||
X509_NAME_oneline(X509_get_subject_name(cert), buf, 256);
|
|
||||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||||
err = X509_STORE_CTX_get_error(ctx);
|
|
||||||
if (depth > 0) {
|
if (depth > 0) {
|
||||||
if (!preverify_ok) {
|
if (!preverify_ok) {
|
||||||
spice_warning("Error in certificate chain verification: %s (num=%d:depth%d:%s)",
|
SPICE_DEBUG("openssl verify failed at depth=%d", depth);
|
||||||
X509_verify_cert_error_string(err), err, depth, buf);
|
|
||||||
v->all_preverify_ok = 0;
|
v->all_preverify_ok = 0;
|
||||||
|
|
||||||
/* if certificate verification failed, we can still authorize the server */
|
|
||||||
/* if its public key matches the one we hold in the peer_connect_options. */
|
|
||||||
if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN &&
|
|
||||||
v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
|
|
||||||
spice_debug("server certificate not being signed by the provided CA");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* depth == 0 */
|
/* depth == 0 */
|
||||||
|
cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
spice_debug("failed to get server certificate");
|
SPICE_DEBUG("failed to get server certificate");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
failed_verifications = 0;
|
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY &&
|
||||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY) {
|
verify_pubkey(cert, v->pubkey, v->pubkey_size))
|
||||||
if (verify_pubkey(cert, v->pubkey, v->pubkey_size))
|
return 1;
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
failed_verifications |= SPICE_SSL_VERIFY_OP_PUBKEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!preverify_ok) {
|
if (!v->all_preverify_ok || !preverify_ok)
|
||||||
err = X509_STORE_CTX_get_error(ctx);
|
|
||||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
|
||||||
spice_warning("Error in server certificate verification: %s (num=%d:depth%d:%s)",
|
|
||||||
X509_verify_cert_error_string(err), err, depth, buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
if (!v->all_preverify_ok) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT) {
|
if (v->verifyop & SPICE_SSL_VERIFY_OP_HOSTNAME &&
|
||||||
if (verify_subject(cert, v))
|
verify_hostname(cert, v->hostname))
|
||||||
return 1;
|
return 1;
|
||||||
else
|
|
||||||
failed_verifications |= SPICE_SSL_VERIFY_OP_SUBJECT;
|
|
||||||
} else if (v->verifyop & SPICE_SSL_VERIFY_OP_HOSTNAME) {
|
|
||||||
if (verify_hostname(cert, v->hostname))
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
failed_verifications |= SPICE_SSL_VERIFY_OP_HOSTNAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we reach this code, this means all the tests failed, thus
|
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT &&
|
||||||
* verification failed
|
verify_subject(cert, v))
|
||||||
*/
|
return 1;
|
||||||
if (failed_verifications & SPICE_SSL_VERIFY_OP_PUBKEY)
|
|
||||||
spice_warning("ssl: pubkey verification failed");
|
|
||||||
|
|
||||||
if (failed_verifications & SPICE_SSL_VERIFY_OP_HOSTNAME)
|
|
||||||
spice_warning("ssl: hostname '%s' verification failed", v->hostname);
|
|
||||||
|
|
||||||
if (failed_verifications & SPICE_SSL_VERIFY_OP_SUBJECT)
|
|
||||||
spice_warning("ssl: subject '%s' verification failed", v->subject);
|
|
||||||
|
|
||||||
spice_warning("ssl: verification failed");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -551,6 +473,9 @@ void spice_openssl_verify_free(SpiceOpenSSLVerify* verify)
|
|||||||
free(verify->subject);
|
free(verify->subject);
|
||||||
free(verify->hostname);
|
free(verify->hostname);
|
||||||
|
|
||||||
|
if (verify->in_subject)
|
||||||
|
X509_NAME_free(verify->in_subject);
|
||||||
|
|
||||||
if (verify->ssl)
|
if (verify->ssl)
|
||||||
SSL_set_app_data(verify->ssl, NULL);
|
SSL_set_app_data(verify->ssl, NULL);
|
||||||
free(verify);
|
free(verify);
|
||||||
|
|||||||
@ -16,16 +16,12 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_SSL_VERIFY
|
#ifndef SSL_VERIFY_H
|
||||||
#define H_SPICE_COMMON_SSL_VERIFY
|
#define SSL_VERIFY_H
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32) && !defined(__MINGW32__)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <wincrypt.h>
|
#include <wincrypt.h>
|
||||||
#ifdef X509_NAME
|
|
||||||
/* wincrypt.h has already a different define... */
|
|
||||||
#undef X509_NAME
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
@ -33,11 +29,12 @@
|
|||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#undef X509_NAME
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
#include <spice/macros.h>
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
SPICE_BEGIN_DECLS
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPICE_SSL_VERIFY_OP_NONE = 0,
|
SPICE_SSL_VERIFY_OP_NONE = 0,
|
||||||
@ -54,6 +51,7 @@ typedef struct {
|
|||||||
char *pubkey;
|
char *pubkey;
|
||||||
size_t pubkey_size;
|
size_t pubkey_size;
|
||||||
char *subject;
|
char *subject;
|
||||||
|
X509_NAME *in_subject;
|
||||||
} SpiceOpenSSLVerify;
|
} SpiceOpenSSLVerify;
|
||||||
|
|
||||||
SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verifyop,
|
SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verifyop,
|
||||||
@ -62,6 +60,7 @@ SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verif
|
|||||||
const char *subject);
|
const char *subject);
|
||||||
void spice_openssl_verify_free(SpiceOpenSSLVerify* verify);
|
void spice_openssl_verify_free(SpiceOpenSSLVerify* verify);
|
||||||
|
|
||||||
SPICE_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
#endif // H_SPICE_COMMON_SSL_VERIFY
|
#endif // __cplusplus
|
||||||
|
#endif // SSL_VERIFY_H
|
||||||
|
|||||||
@ -15,13 +15,21 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
#undef HAVE_STDLIB_H
|
#undef HAVE_STDLIB_H
|
||||||
#endif
|
#endif
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SPICE_CANVAS_INTERNAL
|
||||||
|
#error "This file shouldn't be compiled directly"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "sw_canvas.h"
|
#include "sw_canvas.h"
|
||||||
|
#define CANVAS_USE_PIXMAN
|
||||||
|
#define CANVAS_SINGLE_INSTANCE
|
||||||
#include "canvas_base.c"
|
#include "canvas_base.c"
|
||||||
#include "rect.h"
|
#include "rect.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
@ -75,33 +83,15 @@ static pixman_image_t *canvas_get_pixman_brush(SwCanvas *canvas,
|
|||||||
case SPICE_BRUSH_TYPE_NONE:
|
case SPICE_BRUSH_TYPE_NONE:
|
||||||
return NULL;
|
return NULL;
|
||||||
default:
|
default:
|
||||||
spice_warn_if_reached();
|
CANVAS_ERROR("invalid brush type");
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static pixman_image_t *get_image(SpiceCanvas *canvas, int force_opaque)
|
static pixman_image_t *get_image(SpiceCanvas *canvas)
|
||||||
{
|
{
|
||||||
SwCanvas *sw_canvas = (SwCanvas *)canvas;
|
SwCanvas *sw_canvas = (SwCanvas *)canvas;
|
||||||
pixman_format_code_t format;
|
|
||||||
|
|
||||||
spice_pixman_image_get_format(sw_canvas->image, &format);
|
pixman_image_ref(sw_canvas->image);
|
||||||
if (force_opaque && PIXMAN_FORMAT_A (format) != 0) {
|
|
||||||
uint32_t *data;
|
|
||||||
int stride;
|
|
||||||
int width, height;
|
|
||||||
|
|
||||||
/* Remove alpha bits from format */
|
|
||||||
format = (pixman_format_code_t)(((uint32_t)format) & ~(0xf << 12));
|
|
||||||
data = pixman_image_get_data(sw_canvas->image);
|
|
||||||
stride = pixman_image_get_stride(sw_canvas->image);
|
|
||||||
width = pixman_image_get_width(sw_canvas->image);
|
|
||||||
height = pixman_image_get_height(sw_canvas->image);
|
|
||||||
return pixman_image_create_bits(format, width, height, data, stride);
|
|
||||||
} else {
|
|
||||||
pixman_image_ref(sw_canvas->image);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sw_canvas->image;
|
return sw_canvas->image;
|
||||||
}
|
}
|
||||||
@ -353,8 +343,8 @@ static void clear_dest_alpha(pixman_image_t *dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
stride = pixman_image_get_stride(dest);
|
stride = pixman_image_get_stride(dest);
|
||||||
data = SPICE_ALIGNED_CAST(uint32_t *,
|
data = (uint32_t *) (
|
||||||
(uint8_t *)pixman_image_get_data(dest) + y * stride + 4 * x);
|
(uint8_t *)pixman_image_get_data(dest) + y * stride + 4 * x);
|
||||||
|
|
||||||
if ((*data & 0xff000000U) == 0xff000000U) {
|
if ((*data & 0xff000000U) == 0xff000000U) {
|
||||||
spice_pixman_fill_rect_rop(dest,
|
spice_pixman_fill_rect_rop(dest,
|
||||||
@ -482,13 +472,13 @@ static void __scale_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
pixman_transform_init_scale(&transform, fsx, fsy);
|
pixman_transform_init_scale(&transform, fsx, fsy);
|
||||||
pixman_transform_translate(&transform, NULL,
|
pixman_transform_translate(&transform, NULL,
|
||||||
pixman_int_to_fixed(src_x),
|
pixman_int_to_fixed (src_x),
|
||||||
pixman_int_to_fixed(src_y));
|
pixman_int_to_fixed (src_y));
|
||||||
|
|
||||||
pixman_image_set_transform(src, &transform);
|
pixman_image_set_transform(src, &transform);
|
||||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||||
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||||
pixman_image_set_filter(src,
|
pixman_image_set_filter(src,
|
||||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||||
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
||||||
@ -549,13 +539,11 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
|
|||||||
pixman_box32_t *rects;
|
pixman_box32_t *rects;
|
||||||
int n_rects, i;
|
int n_rects, i;
|
||||||
pixman_fixed_t fsx, fsy;
|
pixman_fixed_t fsx, fsy;
|
||||||
pixman_format_code_t format;
|
|
||||||
|
|
||||||
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
||||||
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
|
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
|
||||||
|
|
||||||
spice_return_if_fail(spice_pixman_image_get_format(src, &format));
|
scaled = pixman_image_create_bits(spice_pixman_image_get_format(src),
|
||||||
scaled = pixman_image_create_bits(format,
|
|
||||||
dest_width,
|
dest_width,
|
||||||
dest_height,
|
dest_height,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
@ -565,13 +553,13 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
pixman_transform_init_scale(&transform, fsx, fsy);
|
pixman_transform_init_scale(&transform, fsx, fsy);
|
||||||
pixman_transform_translate(&transform, NULL,
|
pixman_transform_translate(&transform, NULL,
|
||||||
pixman_int_to_fixed(src_x),
|
pixman_int_to_fixed (src_x),
|
||||||
pixman_int_to_fixed(src_y));
|
pixman_int_to_fixed (src_y));
|
||||||
|
|
||||||
pixman_image_set_transform(src, &transform);
|
pixman_image_set_transform(src, &transform);
|
||||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||||
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||||
pixman_image_set_filter(src,
|
pixman_image_set_filter(src,
|
||||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||||
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
||||||
@ -671,7 +659,7 @@ static void __blend_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
if (overall_alpha != 0xff) {
|
if (overall_alpha != 0xff) {
|
||||||
pixman_color_t color = { 0, 0, 0, 0 };
|
pixman_color_t color = { 0 };
|
||||||
color.alpha = overall_alpha * 0x101;
|
color.alpha = overall_alpha * 0x101;
|
||||||
mask = pixman_image_create_solid_fill(&color);
|
mask = pixman_image_create_solid_fill(&color);
|
||||||
}
|
}
|
||||||
@ -759,20 +747,20 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
pixman_transform_init_scale(&transform, fsx, fsy);
|
pixman_transform_init_scale(&transform, fsx, fsy);
|
||||||
pixman_transform_translate(&transform, NULL,
|
pixman_transform_translate(&transform, NULL,
|
||||||
pixman_int_to_fixed(src_x),
|
pixman_int_to_fixed (src_x),
|
||||||
pixman_int_to_fixed(src_y));
|
pixman_int_to_fixed (src_y));
|
||||||
|
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
if (overall_alpha != 0xff) {
|
if (overall_alpha != 0xff) {
|
||||||
pixman_color_t color = { 0, 0, 0, 0 };
|
pixman_color_t color = { 0 };
|
||||||
color.alpha = overall_alpha * 0x101;
|
color.alpha = overall_alpha * 0x101;
|
||||||
mask = pixman_image_create_solid_fill(&color);
|
mask = pixman_image_create_solid_fill(&color);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_image_set_transform(src, &transform);
|
pixman_image_set_transform(src, &transform);
|
||||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||||
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||||
pixman_image_set_filter(src,
|
pixman_image_set_filter(src,
|
||||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||||
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
||||||
@ -907,13 +895,11 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
|
|||||||
pixman_box32_t *rects;
|
pixman_box32_t *rects;
|
||||||
int n_rects, i;
|
int n_rects, i;
|
||||||
pixman_fixed_t fsx, fsy;
|
pixman_fixed_t fsx, fsy;
|
||||||
pixman_format_code_t format;
|
|
||||||
|
|
||||||
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
||||||
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
|
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
|
||||||
|
|
||||||
spice_return_if_fail(spice_pixman_image_get_format(src, &format));
|
scaled = pixman_image_create_bits(spice_pixman_image_get_format (src),
|
||||||
scaled = pixman_image_create_bits(format,
|
|
||||||
dest_width,
|
dest_width,
|
||||||
dest_height,
|
dest_height,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
@ -923,8 +909,8 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
pixman_transform_init_scale(&transform, fsx, fsy);
|
pixman_transform_init_scale(&transform, fsx, fsy);
|
||||||
pixman_transform_translate(&transform, NULL,
|
pixman_transform_translate(&transform, NULL,
|
||||||
pixman_int_to_fixed(src_x),
|
pixman_int_to_fixed (src_x),
|
||||||
pixman_int_to_fixed(src_y));
|
pixman_int_to_fixed (src_y));
|
||||||
|
|
||||||
pixman_image_set_transform(src, &transform);
|
pixman_image_set_transform(src, &transform);
|
||||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||||
@ -991,6 +977,9 @@ static void colorkey_scale_image_from_surface(SpiceCanvas *spice_canvas,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void canvas_put_image(SpiceCanvas *spice_canvas,
|
static void canvas_put_image(SpiceCanvas *spice_canvas,
|
||||||
|
#ifdef WIN32
|
||||||
|
HDC dc,
|
||||||
|
#endif
|
||||||
const SpiceRect *dest, const uint8_t *src_data,
|
const SpiceRect *dest, const uint8_t *src_data,
|
||||||
uint32_t src_width, uint32_t src_height, int src_stride,
|
uint32_t src_width, uint32_t src_height, int src_stride,
|
||||||
const QRegion *clip)
|
const QRegion *clip)
|
||||||
@ -1005,7 +994,7 @@ static void canvas_put_image(SpiceCanvas *spice_canvas,
|
|||||||
src = pixman_image_create_bits(PIXMAN_x8r8g8b8,
|
src = pixman_image_create_bits(PIXMAN_x8r8g8b8,
|
||||||
src_width,
|
src_width,
|
||||||
src_height,
|
src_height,
|
||||||
SPICE_ALIGNED_CAST(uint32_t*,src_data),
|
(uint32_t*)src_data,
|
||||||
src_stride);
|
src_stride);
|
||||||
|
|
||||||
|
|
||||||
@ -1053,7 +1042,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
|||||||
pixman_region32_t dest_region;
|
pixman_region32_t dest_region;
|
||||||
pixman_image_t *str_mask, *brush;
|
pixman_image_t *str_mask, *brush;
|
||||||
SpiceString *str;
|
SpiceString *str;
|
||||||
SpicePoint pos = { 0, 0 };
|
SpicePoint pos;
|
||||||
int depth;
|
int depth;
|
||||||
|
|
||||||
pixman_region32_init_rect(&dest_region,
|
pixman_region32_init_rect(&dest_region,
|
||||||
@ -1075,7 +1064,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
|||||||
|
|
||||||
/* Nothing else makes sense for text and we should deprecate it
|
/* Nothing else makes sense for text and we should deprecate it
|
||||||
* and actually it means OVER really */
|
* and actually it means OVER really */
|
||||||
spice_return_if_fail(text->fore_mode == SPICE_ROPD_OP_PUT);
|
ASSERT(text->fore_mode == SPICE_ROPD_OP_PUT);
|
||||||
|
|
||||||
pixman_region32_init_rect(&back_region,
|
pixman_region32_init_rect(&back_region,
|
||||||
text->back_area.left,
|
text->back_area.left,
|
||||||
@ -1098,10 +1087,10 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
|||||||
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
|
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
|
||||||
depth = 4;
|
depth = 4;
|
||||||
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
|
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
|
||||||
spice_warning("untested path A8 glyphs");
|
WARN("untested path A8 glyphs");
|
||||||
depth = 8;
|
depth = 8;
|
||||||
} else {
|
} else {
|
||||||
spice_warning("unsupported path vector glyphs");
|
WARN("unsupported path vector glyphs");
|
||||||
pixman_region32_fini (&dest_region);
|
pixman_region32_fini (&dest_region);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1144,7 +1133,7 @@ static void canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest,
|
|||||||
uint8_t *dest_end;
|
uint8_t *dest_end;
|
||||||
int bpp;
|
int bpp;
|
||||||
|
|
||||||
spice_return_if_fail(canvas && area);
|
ASSERT(canvas && area);
|
||||||
|
|
||||||
surface = canvas->image;
|
surface = canvas->image;
|
||||||
|
|
||||||
@ -1181,37 +1170,47 @@ static void canvas_destroy(SpiceCanvas *spice_canvas)
|
|||||||
free(canvas);
|
free(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int need_init = 1;
|
||||||
static SpiceCanvasOps sw_canvas_ops;
|
static SpiceCanvasOps sw_canvas_ops;
|
||||||
|
|
||||||
static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
||||||
uint32_t format,
|
uint32_t format
|
||||||
SpiceImageCache *bits_cache,
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
SpicePaletteCache *palette_cache,
|
, SpiceImageCache *bits_cache
|
||||||
|
, SpicePaletteCache *palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
#endif
|
#endif
|
||||||
SpiceImageSurfaces *surfaces,
|
, SpiceImageSurfaces *surfaces
|
||||||
SpiceGlzDecoder *glz_decoder,
|
, SpiceGlzDecoder *glz_decoder
|
||||||
SpiceJpegDecoder *jpeg_decoder,
|
, SpiceJpegDecoder *jpeg_decoder
|
||||||
SpiceZlibDecoder *zlib_decoder)
|
, SpiceZlibDecoder *zlib_decoder
|
||||||
|
)
|
||||||
{
|
{
|
||||||
SwCanvas *canvas;
|
SwCanvas *canvas;
|
||||||
|
|
||||||
|
if (need_init) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
spice_pixman_image_set_format(image,
|
spice_pixman_image_set_format(image,
|
||||||
spice_surface_format_to_pixman(format));
|
spice_surface_format_to_pixman (format));
|
||||||
|
|
||||||
canvas = spice_new0(SwCanvas, 1);
|
canvas = spice_new0(SwCanvas, 1);
|
||||||
canvas_base_init(&canvas->base, &sw_canvas_ops,
|
canvas_base_init(&canvas->base, &sw_canvas_ops,
|
||||||
pixman_image_get_width(image),
|
pixman_image_get_width (image),
|
||||||
pixman_image_get_height(image),
|
pixman_image_get_height (image),
|
||||||
format,
|
format
|
||||||
bits_cache,
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
palette_cache,
|
, bits_cache
|
||||||
|
, palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, bits_cache
|
||||||
#endif
|
#endif
|
||||||
surfaces,
|
, surfaces
|
||||||
glz_decoder,
|
, glz_decoder
|
||||||
jpeg_decoder,
|
, jpeg_decoder
|
||||||
zlib_decoder);
|
, zlib_decoder
|
||||||
|
);
|
||||||
canvas->private_data = NULL;
|
canvas->private_data = NULL;
|
||||||
canvas->private_data_size = 0;
|
canvas->private_data_size = 0;
|
||||||
|
|
||||||
@ -1220,37 +1219,78 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
|||||||
return (SpiceCanvas *)canvas;
|
return (SpiceCanvas *)canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
|
SpiceCanvas *canvas_create(int width, int height, uint32_t format
|
||||||
uint8_t *data, int stride,
|
|
||||||
SpiceImageCache *bits_cache,
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
SpicePaletteCache *palette_cache,
|
, SpiceImageCache *bits_cache
|
||||||
|
, SpicePaletteCache *palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
#endif
|
#endif
|
||||||
SpiceImageSurfaces *surfaces,
|
, SpiceImageSurfaces *surfaces
|
||||||
SpiceGlzDecoder *glz_decoder,
|
, SpiceGlzDecoder *glz_decoder
|
||||||
SpiceJpegDecoder *jpeg_decoder,
|
, SpiceJpegDecoder *jpeg_decoder
|
||||||
SpiceZlibDecoder *zlib_decoder)
|
, SpiceZlibDecoder *zlib_decoder
|
||||||
|
)
|
||||||
{
|
{
|
||||||
pixman_image_t *image;
|
pixman_image_t *image;
|
||||||
|
|
||||||
image = pixman_image_create_bits(spice_surface_format_to_pixman(format),
|
image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
|
||||||
width, height,
|
width, height, NULL, 0);
|
||||||
SPICE_ALIGNED_CAST(uint32_t *,data),
|
|
||||||
stride);
|
|
||||||
|
|
||||||
return canvas_create_common(image, format,
|
return canvas_create_common(image, format
|
||||||
bits_cache,
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
palette_cache,
|
, bits_cache
|
||||||
|
, palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, bits_cache
|
||||||
#endif
|
#endif
|
||||||
surfaces,
|
, surfaces
|
||||||
glz_decoder,
|
, glz_decoder
|
||||||
jpeg_decoder,
|
, jpeg_decoder
|
||||||
zlib_decoder);
|
, zlib_decoder
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPICE_CONSTRUCTOR_FUNC(sw_canvas_global_init) //unsafe global function
|
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
|
||||||
|
uint8_t *data, int stride
|
||||||
|
#ifdef SW_CANVAS_CACHE
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
|
, SpicePaletteCache *palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
|
#endif
|
||||||
|
, SpiceImageSurfaces *surfaces
|
||||||
|
, SpiceGlzDecoder *glz_decoder
|
||||||
|
, SpiceJpegDecoder *jpeg_decoder
|
||||||
|
, SpiceZlibDecoder *zlib_decoder
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
pixman_image_t *image;
|
||||||
|
|
||||||
|
image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
|
||||||
|
width, height, (uint32_t *)data, stride);
|
||||||
|
|
||||||
|
return canvas_create_common(image, format
|
||||||
|
#ifdef SW_CANVAS_CACHE
|
||||||
|
, bits_cache
|
||||||
|
, palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, bits_cache
|
||||||
|
#endif
|
||||||
|
, surfaces
|
||||||
|
, glz_decoder
|
||||||
|
, jpeg_decoder
|
||||||
|
, zlib_decoder
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sw_canvas_init(void) //unsafe global function
|
||||||
|
{
|
||||||
|
if (!need_init) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
need_init = 0;
|
||||||
|
|
||||||
canvas_base_init_ops(&sw_canvas_ops);
|
canvas_base_init_ops(&sw_canvas_ops);
|
||||||
sw_canvas_ops.draw_text = canvas_draw_text;
|
sw_canvas_ops.draw_text = canvas_draw_text;
|
||||||
sw_canvas_ops.put_image = canvas_put_image;
|
sw_canvas_ops.put_image = canvas_put_image;
|
||||||
@ -1283,4 +1323,5 @@ SPICE_CONSTRUCTOR_FUNC(sw_canvas_global_init) //unsafe global function
|
|||||||
sw_canvas_ops.colorkey_scale_image_from_surface = colorkey_scale_image_from_surface;
|
sw_canvas_ops.colorkey_scale_image_from_surface = colorkey_scale_image_from_surface;
|
||||||
sw_canvas_ops.copy_region = copy_region;
|
sw_canvas_ops.copy_region = copy_region;
|
||||||
sw_canvas_ops.get_image = get_image;
|
sw_canvas_ops.get_image = get_image;
|
||||||
|
rop3_init();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,23 +16,43 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_SW_CANVAS
|
#ifndef _H__CANVAS
|
||||||
#define H_SPICE_COMMON_SW_CANVAS
|
#define _H__CANVAS
|
||||||
|
|
||||||
|
#ifndef SPICE_CANVAS_INTERNAL
|
||||||
|
#error "This header shouldn't be included directly"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
#include "canvas_base.h"
|
#include "canvas_base.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SpiceCanvas *canvas_create(int width, int height, uint32_t format
|
||||||
|
#ifdef SW_CANVAS_CACHE
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
|
, SpicePaletteCache *palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
|
#endif
|
||||||
|
, SpiceImageSurfaces *surfaces
|
||||||
|
, SpiceGlzDecoder *glz_decoder
|
||||||
|
, SpiceJpegDecoder *jpeg_decoder
|
||||||
|
, SpiceZlibDecoder *zlib_decoder
|
||||||
|
);
|
||||||
|
|
||||||
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, int stride
|
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, int stride
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
, SpicePaletteCache *palette_cache
|
, SpicePaletteCache *palette_cache
|
||||||
|
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
#endif
|
#endif
|
||||||
, SpiceImageSurfaces *surfaces
|
, SpiceImageSurfaces *surfaces
|
||||||
, SpiceGlzDecoder *glz_decoder
|
, SpiceGlzDecoder *glz_decoder
|
||||||
@ -41,6 +61,10 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
SPICE_END_DECLS
|
void sw_canvas_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2023 Intel Corporation.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include "udev.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_UDEV
|
|
||||||
#include <libudev.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
GpuVendor spice_udev_detect_gpu(int gpu_vendor)
|
|
||||||
{
|
|
||||||
struct udev *udev;
|
|
||||||
struct udev_device *drm_dev, *pci_dev;
|
|
||||||
struct udev_enumerate *udev_enum;
|
|
||||||
struct udev_list_entry *entry, *devices;
|
|
||||||
const char *path, *vendor_id;
|
|
||||||
GpuVendor vendor = VENDOR_GPU_NOTDETECTED;
|
|
||||||
|
|
||||||
udev = udev_new();
|
|
||||||
if (!udev) {
|
|
||||||
return VENDOR_GPU_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
udev_enum = udev_enumerate_new(udev);
|
|
||||||
if (udev_enum) {
|
|
||||||
udev_enumerate_add_match_subsystem(udev_enum, "drm");
|
|
||||||
udev_enumerate_add_match_sysname(udev_enum, "card[0-9]");
|
|
||||||
udev_enumerate_scan_devices(udev_enum);
|
|
||||||
devices = udev_enumerate_get_list_entry(udev_enum);
|
|
||||||
|
|
||||||
udev_list_entry_foreach(entry, devices) {
|
|
||||||
path = udev_list_entry_get_name(entry);
|
|
||||||
drm_dev = udev_device_new_from_syspath(udev, path);
|
|
||||||
if (!drm_dev) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_dev = udev_device_get_parent_with_subsystem_devtype(drm_dev,
|
|
||||||
"pci", NULL);
|
|
||||||
if (pci_dev) {
|
|
||||||
vendor_id = udev_device_get_sysattr_value(pci_dev, "vendor");
|
|
||||||
if (vendor_id && strtol(vendor_id, NULL, 16) == gpu_vendor) {
|
|
||||||
vendor = VENDOR_GPU_DETECTED;
|
|
||||||
udev_device_unref(drm_dev);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
udev_device_unref(drm_dev);
|
|
||||||
}
|
|
||||||
udev_enumerate_unref(udev_enum);
|
|
||||||
}
|
|
||||||
udev_unref(udev);
|
|
||||||
|
|
||||||
return vendor;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
GpuVendor spice_udev_detect_gpu(int gpu_vendor)
|
|
||||||
{
|
|
||||||
return VENDOR_GPU_UNKNOWN;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2023 Intel Corporation.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#define INTEL_VENDOR_ID 0x8086
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
VENDOR_GPU_UNKNOWN,
|
|
||||||
VENDOR_GPU_DETECTED,
|
|
||||||
VENDOR_GPU_NOTDETECTED,
|
|
||||||
} GpuVendor;
|
|
||||||
|
|
||||||
SPICE_BEGIN_DECLS
|
|
||||||
|
|
||||||
GpuVendor spice_udev_detect_gpu(int gpu_vendor);
|
|
||||||
|
|
||||||
SPICE_END_DECLS
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2010, 2011, 2018 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
/* These 2 functions come from
|
|
||||||
* libvirt-glib/libvirt-gconfig/libvirt-gconfig-helpers.c
|
|
||||||
* Copyright (C) 2010, 2011 Red Hat, Inc.
|
|
||||||
* LGPLv2.1+ licensed */
|
|
||||||
|
|
||||||
const char *
|
|
||||||
spice_genum_get_nick(GType enum_type, gint value)
|
|
||||||
{
|
|
||||||
GEnumClass *enum_class;
|
|
||||||
GEnumValue *enum_value;
|
|
||||||
|
|
||||||
g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), NULL);
|
|
||||||
|
|
||||||
enum_class = g_type_class_ref(enum_type);
|
|
||||||
enum_value = g_enum_get_value(enum_class, value);
|
|
||||||
g_type_class_unref(enum_class);
|
|
||||||
|
|
||||||
if (enum_value != NULL) {
|
|
||||||
return enum_value->value_nick;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_return_val_if_reached(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
spice_genum_get_value(GType enum_type, const char *nick,
|
|
||||||
gint default_value)
|
|
||||||
{
|
|
||||||
GEnumClass *enum_class;
|
|
||||||
GEnumValue *enum_value;
|
|
||||||
|
|
||||||
g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), default_value);
|
|
||||||
g_return_val_if_fail(nick != NULL, default_value);
|
|
||||||
|
|
||||||
enum_class = g_type_class_ref(enum_type);
|
|
||||||
enum_value = g_enum_get_value_by_nick(enum_class, nick);
|
|
||||||
g_type_class_unref(enum_class);
|
|
||||||
|
|
||||||
if (enum_value != NULL) {
|
|
||||||
return enum_value->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_return_val_if_reached(default_value);
|
|
||||||
}
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2010, 2011, 2018 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON_UTILS
|
|
||||||
#define H_SPICE_COMMON_UTILS
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib-object.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
const char *spice_genum_get_nick(GType enum_type, gint value);
|
|
||||||
int spice_genum_get_value(GType enum_type, const char *nick,
|
|
||||||
gint default_value);
|
|
||||||
|
|
||||||
#define BIT_BYTE(nr) ((nr) / 8)
|
|
||||||
#define BIT_MASK(nr) (1 << ((nr) % 8))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set_bitmap - Set a bit in memory
|
|
||||||
* @nr: the bit to set
|
|
||||||
* @addr: the address to start counting from
|
|
||||||
*/
|
|
||||||
static inline void set_bitmap(uint32_t nr, uint8_t *addr)
|
|
||||||
{
|
|
||||||
addr[BIT_BYTE(nr)] |= BIT_MASK(nr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* test_bitmap - Determine whether a bit is set
|
|
||||||
* @nr: bit number to test
|
|
||||||
* @addr: Address to start counting from
|
|
||||||
*/
|
|
||||||
static inline int test_bitmap(uint32_t nr, const uint8_t *addr)
|
|
||||||
{
|
|
||||||
return 1 & (addr[BIT_BYTE(nr)] >> (nr % 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif //H_SPICE_COMMON_UTILS
|
|
||||||
283
common/verify.h
283
common/verify.h
@ -1,283 +0,0 @@
|
|||||||
/* Compile-time assert-like macros.
|
|
||||||
|
|
||||||
Copyright (C) 2005-2006, 2009-2019 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2.1 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This 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 Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
|
|
||||||
|
|
||||||
#ifndef _GL_VERIFY_H
|
|
||||||
#define _GL_VERIFY_H
|
|
||||||
|
|
||||||
|
|
||||||
/* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert works as per C11.
|
|
||||||
This is supported by GCC 4.6.0 and later, in C mode, and its use
|
|
||||||
here generates easier-to-read diagnostics when verify (R) fails.
|
|
||||||
|
|
||||||
Define _GL_HAVE_STATIC_ASSERT to 1 if static_assert works as per C++11.
|
|
||||||
This is supported by GCC 6.1.0 and later, in C++ mode.
|
|
||||||
|
|
||||||
Use this only with GCC. If we were willing to slow 'configure'
|
|
||||||
down we could also use it with other compilers, but since this
|
|
||||||
affects only the quality of diagnostics, why bother? */
|
|
||||||
#if (4 < __GNUC__ + (6 <= __GNUC_MINOR__) \
|
|
||||||
&& (201112L <= __STDC_VERSION__ || !defined __STRICT_ANSI__) \
|
|
||||||
&& !defined __cplusplus)
|
|
||||||
# define _GL_HAVE__STATIC_ASSERT 1
|
|
||||||
#endif
|
|
||||||
#if (6 <= __GNUC__) && defined __cplusplus
|
|
||||||
# define _GL_HAVE_STATIC_ASSERT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other
|
|
||||||
system headers, defines a conflicting _Static_assert that is no
|
|
||||||
better than ours; override it. */
|
|
||||||
#ifndef _GL_HAVE_STATIC_ASSERT
|
|
||||||
# include <stddef.h>
|
|
||||||
# undef _Static_assert
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Each of these macros verifies that its argument R is nonzero. To
|
|
||||||
be portable, R should be an integer constant expression. Unlike
|
|
||||||
assert (R), there is no run-time overhead.
|
|
||||||
|
|
||||||
If _Static_assert works, verify (R) uses it directly. Similarly,
|
|
||||||
_GL_VERIFY_TRUE works by packaging a _Static_assert inside a struct
|
|
||||||
that is an operand of sizeof.
|
|
||||||
|
|
||||||
The code below uses several ideas for C++ compilers, and for C
|
|
||||||
compilers that do not support _Static_assert:
|
|
||||||
|
|
||||||
* The first step is ((R) ? 1 : -1). Given an expression R, of
|
|
||||||
integral or boolean or floating-point type, this yields an
|
|
||||||
expression of integral type, whose value is later verified to be
|
|
||||||
constant and nonnegative.
|
|
||||||
|
|
||||||
* Next this expression W is wrapped in a type
|
|
||||||
struct _gl_verify_type {
|
|
||||||
unsigned int _gl_verify_error_if_negative: W;
|
|
||||||
}.
|
|
||||||
If W is negative, this yields a compile-time error. No compiler can
|
|
||||||
deal with a bit-field of negative size.
|
|
||||||
|
|
||||||
One might think that an array size check would have the same
|
|
||||||
effect, that is, that the type struct { unsigned int dummy[W]; }
|
|
||||||
would work as well. However, inside a function, some compilers
|
|
||||||
(such as C++ compilers and GNU C) allow local parameters and
|
|
||||||
variables inside array size expressions. With these compilers,
|
|
||||||
an array size check would not properly diagnose this misuse of
|
|
||||||
the verify macro:
|
|
||||||
|
|
||||||
void function (int n) { verify (n < 0); }
|
|
||||||
|
|
||||||
* For the verify macro, the struct _gl_verify_type will need to
|
|
||||||
somehow be embedded into a declaration. To be portable, this
|
|
||||||
declaration must declare an object, a constant, a function, or a
|
|
||||||
typedef name. If the declared entity uses the type directly,
|
|
||||||
such as in
|
|
||||||
|
|
||||||
struct dummy {...};
|
|
||||||
typedef struct {...} dummy;
|
|
||||||
extern struct {...} *dummy;
|
|
||||||
extern void dummy (struct {...} *);
|
|
||||||
extern struct {...} *dummy (void);
|
|
||||||
|
|
||||||
two uses of the verify macro would yield colliding declarations
|
|
||||||
if the entity names are not disambiguated. A workaround is to
|
|
||||||
attach the current line number to the entity name:
|
|
||||||
|
|
||||||
#define _GL_CONCAT0(x, y) x##y
|
|
||||||
#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
|
|
||||||
extern struct {...} * _GL_CONCAT (dummy, __LINE__);
|
|
||||||
|
|
||||||
But this has the problem that two invocations of verify from
|
|
||||||
within the same macro would collide, since the __LINE__ value
|
|
||||||
would be the same for both invocations. (The GCC __COUNTER__
|
|
||||||
macro solves this problem, but is not portable.)
|
|
||||||
|
|
||||||
A solution is to use the sizeof operator. It yields a number,
|
|
||||||
getting rid of the identity of the type. Declarations like
|
|
||||||
|
|
||||||
extern int dummy [sizeof (struct {...})];
|
|
||||||
extern void dummy (int [sizeof (struct {...})]);
|
|
||||||
extern int (*dummy (void)) [sizeof (struct {...})];
|
|
||||||
|
|
||||||
can be repeated.
|
|
||||||
|
|
||||||
* Should the implementation use a named struct or an unnamed struct?
|
|
||||||
Which of the following alternatives can be used?
|
|
||||||
|
|
||||||
extern int dummy [sizeof (struct {...})];
|
|
||||||
extern int dummy [sizeof (struct _gl_verify_type {...})];
|
|
||||||
extern void dummy (int [sizeof (struct {...})]);
|
|
||||||
extern void dummy (int [sizeof (struct _gl_verify_type {...})]);
|
|
||||||
extern int (*dummy (void)) [sizeof (struct {...})];
|
|
||||||
extern int (*dummy (void)) [sizeof (struct _gl_verify_type {...})];
|
|
||||||
|
|
||||||
In the second and sixth case, the struct type is exported to the
|
|
||||||
outer scope; two such declarations therefore collide. GCC warns
|
|
||||||
about the first, third, and fourth cases. So the only remaining
|
|
||||||
possibility is the fifth case:
|
|
||||||
|
|
||||||
extern int (*dummy (void)) [sizeof (struct {...})];
|
|
||||||
|
|
||||||
* GCC warns about duplicate declarations of the dummy function if
|
|
||||||
-Wredundant-decls is used. GCC 4.3 and later have a builtin
|
|
||||||
__COUNTER__ macro that can let us generate unique identifiers for
|
|
||||||
each dummy function, to suppress this warning.
|
|
||||||
|
|
||||||
* This implementation exploits the fact that older versions of GCC,
|
|
||||||
which do not support _Static_assert, also do not warn about the
|
|
||||||
last declaration mentioned above.
|
|
||||||
|
|
||||||
* GCC warns if -Wnested-externs is enabled and verify() is used
|
|
||||||
within a function body; but inside a function, you can always
|
|
||||||
arrange to use verify_expr() instead.
|
|
||||||
|
|
||||||
* In C++, any struct definition inside sizeof is invalid.
|
|
||||||
Use a template type to work around the problem. */
|
|
||||||
|
|
||||||
/* Concatenate two preprocessor tokens. */
|
|
||||||
#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
|
|
||||||
#define _GL_CONCAT0(x, y) x##y
|
|
||||||
|
|
||||||
/* _GL_COUNTER is an integer, preferably one that changes each time we
|
|
||||||
use it. Use __COUNTER__ if it works, falling back on __LINE__
|
|
||||||
otherwise. __LINE__ isn't perfect, but it's better than a
|
|
||||||
constant. */
|
|
||||||
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
|
|
||||||
# define _GL_COUNTER __COUNTER__
|
|
||||||
#else
|
|
||||||
# define _GL_COUNTER __LINE__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Generate a symbol with the given prefix, making it unique if
|
|
||||||
possible. */
|
|
||||||
#define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
|
|
||||||
|
|
||||||
/* Verify requirement R at compile-time, as an integer constant expression
|
|
||||||
that returns 1. If R is false, fail at compile-time, preferably
|
|
||||||
with a diagnostic that includes the string-literal DIAGNOSTIC. */
|
|
||||||
|
|
||||||
#define _GL_VERIFY_TRUE(R, DIAGNOSTIC) \
|
|
||||||
(!!sizeof (_GL_VERIFY_TYPE (R, DIAGNOSTIC)))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
# if !GNULIB_defined_struct__gl_verify_type
|
|
||||||
template <int w>
|
|
||||||
struct _gl_verify_type {
|
|
||||||
unsigned int _gl_verify_error_if_negative: w;
|
|
||||||
};
|
|
||||||
# define GNULIB_defined_struct__gl_verify_type 1
|
|
||||||
# endif
|
|
||||||
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
|
||||||
_gl_verify_type<(R) ? 1 : -1>
|
|
||||||
#elif defined _GL_HAVE__STATIC_ASSERT
|
|
||||||
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
|
||||||
struct { \
|
|
||||||
_Static_assert (R, DIAGNOSTIC); \
|
|
||||||
int _gl_dummy; \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
|
||||||
struct { unsigned int _gl_verify_error_if_negative: (R) ? 1 : -1; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Verify requirement R at compile-time, as a declaration without a
|
|
||||||
trailing ';'. If R is false, fail at compile-time, preferably
|
|
||||||
with a diagnostic that includes the string-literal DIAGNOSTIC.
|
|
||||||
|
|
||||||
Unfortunately, unlike C11, this implementation must appear as an
|
|
||||||
ordinary declaration, and cannot appear inside struct { ... }. */
|
|
||||||
|
|
||||||
#ifdef _GL_HAVE__STATIC_ASSERT
|
|
||||||
# define _GL_VERIFY _Static_assert
|
|
||||||
#else
|
|
||||||
# define _GL_VERIFY(R, DIAGNOSTIC) \
|
|
||||||
extern int (*_GL_GENSYM (_gl_verify_function) (void)) \
|
|
||||||
[_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */
|
|
||||||
#ifdef _GL_STATIC_ASSERT_H
|
|
||||||
# if !defined _GL_HAVE__STATIC_ASSERT && !defined _Static_assert
|
|
||||||
# define _Static_assert(R, DIAGNOSTIC) _GL_VERIFY (R, DIAGNOSTIC)
|
|
||||||
# endif
|
|
||||||
# if !defined _GL_HAVE_STATIC_ASSERT && !defined static_assert
|
|
||||||
# define static_assert _Static_assert /* C11 requires this #define. */
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* @assert.h omit start@ */
|
|
||||||
|
|
||||||
/* Each of these macros verifies that its argument R is nonzero. To
|
|
||||||
be portable, R should be an integer constant expression. Unlike
|
|
||||||
assert (R), there is no run-time overhead.
|
|
||||||
|
|
||||||
There are two macros, since no single macro can be used in all
|
|
||||||
contexts in C. verify_true (R) is for scalar contexts, including
|
|
||||||
integer constant expression contexts. verify (R) is for declaration
|
|
||||||
contexts, e.g., the top level. */
|
|
||||||
|
|
||||||
/* Verify requirement R at compile-time, as an integer constant expression.
|
|
||||||
Return 1. This is equivalent to verify_expr (R, 1).
|
|
||||||
|
|
||||||
verify_true is obsolescent; please use verify_expr instead. */
|
|
||||||
|
|
||||||
#define verify_true(R) _GL_VERIFY_TRUE (R, "verify_true (" #R ")")
|
|
||||||
|
|
||||||
/* Verify requirement R at compile-time. Return the value of the
|
|
||||||
expression E. */
|
|
||||||
|
|
||||||
#define verify_expr(R, E) \
|
|
||||||
(_GL_VERIFY_TRUE (R, "verify_expr (" #R ", " #E ")") ? (E) : (E))
|
|
||||||
|
|
||||||
/* Verify requirement R at compile-time, as a declaration without a
|
|
||||||
trailing ';'. */
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
# define verify(R) _GL_VERIFY (R, "verify (" #R ")")
|
|
||||||
#else
|
|
||||||
/* PGI barfs if R is long. Play it safe. */
|
|
||||||
# define verify(R) _GL_VERIFY (R, "verify (...)")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __has_builtin
|
|
||||||
# define __has_builtin(x) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Assume that R always holds. This lets the compiler optimize
|
|
||||||
accordingly. R should not have side-effects; it may or may not be
|
|
||||||
evaluated. Behavior is undefined if R is false. */
|
|
||||||
|
|
||||||
#if (__has_builtin (__builtin_unreachable) \
|
|
||||||
|| 4 < __GNUC__ + (5 <= __GNUC_MINOR__))
|
|
||||||
# define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
|
|
||||||
#elif 1200 <= _MSC_VER
|
|
||||||
# define assume(R) __assume (R)
|
|
||||||
#elif ((defined GCC_LINT || defined lint) \
|
|
||||||
&& (__has_builtin (__builtin_trap) \
|
|
||||||
|| 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))))
|
|
||||||
/* Doing it this way helps various packages when configured with
|
|
||||||
--enable-gcc-warnings, which compiles with -Dlint. It's nicer
|
|
||||||
when 'assume' silences warnings even with older GCCs. */
|
|
||||||
# define assume(R) ((R) ? (void) 0 : __builtin_trap ())
|
|
||||||
#else
|
|
||||||
/* Some tools grok NOTREACHED, e.g., Oracle Studio 12.6. */
|
|
||||||
# define assume(R) ((R) ? (void) 0 : /*NOTREACHED*/ (void) 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* @assert.h omit end@ */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
1
common/win/Makefile.am
Normal file
1
common/win/Makefile.am
Normal file
@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = my_getopt-1.5
|
||||||
22
common/win/my_getopt-1.5/ChangeLog
Normal file
22
common/win/my_getopt-1.5/ChangeLog
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
2006-12-09 Benjamin C. W. Sittler <bsittler@>
|
||||||
|
|
||||||
|
* my_getopt.c: add my_getopt_reset to reset the argument parser
|
||||||
|
|
||||||
|
* README: updated email address, updated for version 1.5
|
||||||
|
|
||||||
|
2002-07-26 Benjamin C. W. Sittler <bsittler@knownow.com>
|
||||||
|
|
||||||
|
* README: updated for version 1.4
|
||||||
|
|
||||||
|
* my_getopt.c: now we include <sys/types.h> explicitly for those
|
||||||
|
systems that narrowly (mis-)interpret ANSI C and POSIX
|
||||||
|
(_my_getopt_internal): added an explicit cast to size_t to make
|
||||||
|
g++ happy
|
||||||
|
|
||||||
|
* getopt.h, my_getopt.h: added extern "C" { ... } for C++
|
||||||
|
compilation (thanks to Jeff Lawson <bovine@ud.com> and others)
|
||||||
|
|
||||||
|
2001-08-20 Benjamin C. W. Sittler <bsittler@knownow.com>
|
||||||
|
|
||||||
|
* getopt.h (getopt_long_only): fixed typo (thanks to Justin Lee
|
||||||
|
<justin_lee@ud.com>)
|
||||||
22
common/win/my_getopt-1.5/LICENSE
Normal file
22
common/win/my_getopt-1.5/LICENSE
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
my_getopt - a command-line argument parser
|
||||||
|
Copyright 1997-2001, Benjamin Sittler
|
||||||
|
|
||||||
|
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 shall 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.
|
||||||
14
common/win/my_getopt-1.5/Makefile.am
Normal file
14
common/win/my_getopt-1.5/Makefile.am
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
NULL =
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
ChangeLog \
|
||||||
|
getopt.3 \
|
||||||
|
getopt.h \
|
||||||
|
getopt.txt \
|
||||||
|
LICENSE \
|
||||||
|
main.c \
|
||||||
|
Makefile \
|
||||||
|
my_getopt.c \
|
||||||
|
my_getopt.h \
|
||||||
|
README \
|
||||||
|
$(NULL)
|
||||||
26
common/win/my_getopt-1.5/Makefile.test
Normal file
26
common/win/my_getopt-1.5/Makefile.test
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
all: copy
|
||||||
|
|
||||||
|
# Compiler options
|
||||||
|
#CCOPTS = -g -O3 -Wall -Werror
|
||||||
|
CCOPTS =
|
||||||
|
|
||||||
|
# Compiler
|
||||||
|
CC = gcc -Wall -Werror
|
||||||
|
#CC = cc
|
||||||
|
|
||||||
|
# Linker
|
||||||
|
LD = $(CC)
|
||||||
|
|
||||||
|
# Utility to remove a file
|
||||||
|
RM = rm
|
||||||
|
|
||||||
|
OBJS = main.o my_getopt.o
|
||||||
|
|
||||||
|
copy: $(OBJS)
|
||||||
|
$(LD) -o $@ $(OBJS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f copy $(OBJS) *~
|
||||||
|
|
||||||
|
%.o: %.c getopt.h my_getopt.h
|
||||||
|
$(CC) $(CCOPTS) -o $@ -c $<
|
||||||
140
common/win/my_getopt-1.5/README
Normal file
140
common/win/my_getopt-1.5/README
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
my_getopt - a command-line argument parser
|
||||||
|
Copyright 1997-2006, Benjamin Sittler
|
||||||
|
|
||||||
|
The author can be reached by sending email to <bsittler@gmail.com>.
|
||||||
|
|
||||||
|
The version of my_getopt in this package (1.5) has a BSD-like license;
|
||||||
|
see the file LICENSE for details. Version 1.0 of my_getopt was similar
|
||||||
|
to the GPL'ed version of my_getopt included with SMOKE-16 Version 1,
|
||||||
|
Release 19990717. SMOKE-16 packages are available from:
|
||||||
|
|
||||||
|
http://geocities.com/bsittler/#smoke16
|
||||||
|
|
||||||
|
OVERVIEW OF THE ARGUMENT PARSER
|
||||||
|
===============================
|
||||||
|
|
||||||
|
The getopt(), getopt_long() and getopt_long_only() functions parse
|
||||||
|
command line arguments. The argc and argv parameters passed to these
|
||||||
|
functions correspond to the argument count and argument list passed to
|
||||||
|
your program's main() function at program start-up. Element 0 of the
|
||||||
|
argument list conventionally contains the name of your program. Any
|
||||||
|
remaining arguments starting with "-" (except for "-" or "--" by
|
||||||
|
themselves) are option arguments, some of include option values. This
|
||||||
|
family of getopt() functions allows intermixed option and non-option
|
||||||
|
arguments anywhere in the argument list, except that "--" by itself
|
||||||
|
causes the remaining elements of the argument list to be treated as
|
||||||
|
non-option arguments.
|
||||||
|
|
||||||
|
[ See the parts of this document labeled "DOCUMENTATION" and
|
||||||
|
"WHY RE-INVENT THE WHEEL?" for a more information. ]
|
||||||
|
|
||||||
|
FILES
|
||||||
|
=====
|
||||||
|
|
||||||
|
The following four files constitute the my_getopt package:
|
||||||
|
|
||||||
|
LICENSE - license and warranty information for my_getopt
|
||||||
|
my_getopt.c - implementation of my getopt replacement
|
||||||
|
my_getopt.h - interface for my getopt replacement
|
||||||
|
getopt.h - a header file to make my getopt look like GNU getopt
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
=====
|
||||||
|
|
||||||
|
To use my_getopt in your application, include the following line to
|
||||||
|
your main program source:
|
||||||
|
|
||||||
|
#include "getopt.h"
|
||||||
|
|
||||||
|
This line should appear after your standard system header files to
|
||||||
|
avoid conflicting with your system's built-in getopt.
|
||||||
|
|
||||||
|
Then compile my_getopt.c into my_getopt.o, and link my_getopt.o into
|
||||||
|
your application:
|
||||||
|
|
||||||
|
$ cc -c my_getopt.c
|
||||||
|
$ ld -o app app.o ... my_getopt.o
|
||||||
|
|
||||||
|
To avoid conflicting with standard library functions, the function
|
||||||
|
names and global variables used by my_getopt all begin with `my_'. To
|
||||||
|
ensure compatibility with existing C programs, the `getopt.h' header
|
||||||
|
file uses the C preprocessor to redefine names like getopt, optarg,
|
||||||
|
optind, and so forth to my_getopt, my_optarg, my_optind, etc.
|
||||||
|
|
||||||
|
SAMPLE PROGRAM
|
||||||
|
==============
|
||||||
|
|
||||||
|
There is also a public-domain sample program:
|
||||||
|
|
||||||
|
main.c - main() for a sample program using my_getopt
|
||||||
|
Makefile - build script for the sample program (called `copy')
|
||||||
|
|
||||||
|
To build and test the sample program:
|
||||||
|
|
||||||
|
$ make
|
||||||
|
$ ./copy -help
|
||||||
|
$ ./copy -version
|
||||||
|
|
||||||
|
The sample program bears a slight resemblance to the UNIX `cat'
|
||||||
|
utility, but can be used rot13-encode streams, and can redirect output
|
||||||
|
to a file.
|
||||||
|
|
||||||
|
DOCUMENTATION
|
||||||
|
=============
|
||||||
|
|
||||||
|
There is not yet any real documentation for my_getopt. For the moment,
|
||||||
|
use the Linux manual page for getopt. It has its own copyright and
|
||||||
|
license; view the file `getopt.3' in a text editor for more details.
|
||||||
|
|
||||||
|
getopt.3 - the manual page for GNU getopt
|
||||||
|
getopt.txt - preformatted copy of the manual page for GNU getopt,
|
||||||
|
for your convenience
|
||||||
|
|
||||||
|
WHY RE-INVENT THE WHEEL?
|
||||||
|
========================
|
||||||
|
|
||||||
|
I re-implemented getopt, getopt_long, and getopt_long_only because
|
||||||
|
there were noticable bugs in several versions of the GNU
|
||||||
|
implementations, and because the GNU versions aren't always available
|
||||||
|
on some systems (*BSD, for example.) Other systems don't include any
|
||||||
|
sort of standard argument parser (Win32 with Microsoft tools, for
|
||||||
|
example, has no getopt.)
|
||||||
|
|
||||||
|
These should do all the expected Unix- and GNU-style argument
|
||||||
|
parsing, including permution, bunching, long options with single or
|
||||||
|
double dashes (double dashes are required if you use
|
||||||
|
my_getopt_long,) and optional arguments for both long and short
|
||||||
|
options. A word with double dashes all by themselves halts argument
|
||||||
|
parsing. A required long option argument can be in the same word as
|
||||||
|
the option name, separated by '=', or in the next word. An optional
|
||||||
|
long option argument must be in the same word as the option name,
|
||||||
|
separated by '='.
|
||||||
|
|
||||||
|
As with the GNU versions, a '+' prefix to the short option
|
||||||
|
specification (or the POSIXLY_CORRECT environment variable) disables
|
||||||
|
permution, a '-' prefix to the short option specification returns 1
|
||||||
|
for non-options, ':' after a short option indicates a required
|
||||||
|
argument, and '::' after a short option specification indicates an
|
||||||
|
optional argument (which must appear in the same word.) If you'd like
|
||||||
|
to recieve ':' instead of '?' for missing option arguments, prefix the
|
||||||
|
short option specification with ':'.
|
||||||
|
|
||||||
|
The original intent was to re-implement the documented behavior of
|
||||||
|
the GNU versions, but I have found it necessary to emulate some of
|
||||||
|
the undocumented behavior as well. Some programs depend on it.
|
||||||
|
|
||||||
|
KNOWN BUGS
|
||||||
|
==========
|
||||||
|
|
||||||
|
The GNU versions support POSIX-style -W "name=value" long
|
||||||
|
options. Currently, my_getopt does not support these, because I
|
||||||
|
don't have any documentation on them (other than the fact that they
|
||||||
|
are enabled by "W;" in the short option specification.) As a
|
||||||
|
temporary workaround, my_getopt treats "W;" in the short option
|
||||||
|
string identically to "W:".
|
||||||
|
|
||||||
|
The GNU versions support internationalized/localized
|
||||||
|
messages. Currently, my_getopt does not.
|
||||||
|
|
||||||
|
There should be re-entrant versions of all these functions so that
|
||||||
|
multiple threads can parse arguments simultaneously.
|
||||||
288
common/win/my_getopt-1.5/getopt.3
Normal file
288
common/win/my_getopt-1.5/getopt.3
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
.\" (c) 1993 by Thomas Koenig (ig25@rz.uni-karlsruhe.de)
|
||||||
|
.\"
|
||||||
|
.\" Permission is granted to make and distribute verbatim copies of this
|
||||||
|
.\" manual provided the copyright notice and this permission notice are
|
||||||
|
.\" preserved on all copies.
|
||||||
|
.\"
|
||||||
|
.\" Permission is granted to copy and distribute modified versions of this
|
||||||
|
.\" manual under the conditions for verbatim copying, provided that the
|
||||||
|
.\" entire resulting derived work is distributed under the terms of a
|
||||||
|
.\" permission notice identical to this one
|
||||||
|
.\"
|
||||||
|
.\" Since the Linux kernel and libraries are constantly changing, this
|
||||||
|
.\" manual page may be incorrect or out-of-date. The author(s) assume no
|
||||||
|
.\" responsibility for errors or omissions, or for damages resulting from
|
||||||
|
.\" the use of the information contained herein. The author(s) may not
|
||||||
|
.\" have taken the same level of care in the production of this manual,
|
||||||
|
.\" which is licensed free of charge, as they might when working
|
||||||
|
.\" professionally.
|
||||||
|
.\"
|
||||||
|
.\" Formatted or processed versions of this manual, if unaccompanied by
|
||||||
|
.\" the source, must acknowledge the copyright and authors of this work.
|
||||||
|
.\" License.
|
||||||
|
.\" Modified Sat Jul 24 19:27:50 1993 by Rik Faith (faith@cs.unc.edu)
|
||||||
|
.\" Modified Mon Aug 30 22:02:34 1995 by Jim Van Zandt <jrv@vanzandt.mv.com>
|
||||||
|
.\" longindex is a pointer, has_arg can take 3 values, using consistent
|
||||||
|
.\" names for optstring and longindex, "\n" in formats fixed. Documenting
|
||||||
|
.\" opterr and getopt_long_only. Clarified explanations (borrowing heavily
|
||||||
|
.\" from the source code).
|
||||||
|
.TH GETOPT 3 "Aug 30, 1995" "GNU" "Linux Programmer's Manual"
|
||||||
|
.SH NAME
|
||||||
|
getopt \- Parse command line options
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
.B #include <unistd.h>
|
||||||
|
.sp
|
||||||
|
.BI "int getopt(int " argc ", char * const " argv[] ","
|
||||||
|
.BI " const char *" optstring ");"
|
||||||
|
.sp
|
||||||
|
.BI "extern char *" optarg ;
|
||||||
|
.BI "extern int " optind ", " opterr ", " optopt ;
|
||||||
|
.sp
|
||||||
|
.B #include <getopt.h>
|
||||||
|
.sp
|
||||||
|
.BI "int getopt_long(int " argc ", char * const " argv[] ",
|
||||||
|
.BI " const char *" optstring ,
|
||||||
|
.BI " const struct option *" longopts ", int *" longindex ");"
|
||||||
|
.sp
|
||||||
|
.BI "int getopt_long_only(int " argc ", char * const " argv[] ",
|
||||||
|
.BI " const char *" optstring ,
|
||||||
|
.BI " const struct option *" longopts ", int *" longindex ");"
|
||||||
|
.fi
|
||||||
|
.SH DESCRIPTION
|
||||||
|
The
|
||||||
|
.B getopt()
|
||||||
|
function parses the command line arguments. Its arguments
|
||||||
|
.I argc
|
||||||
|
and
|
||||||
|
.I argv
|
||||||
|
are the argument count and array as passed to the
|
||||||
|
.B main()
|
||||||
|
function on program invocation.
|
||||||
|
An element of \fIargv\fP that starts with `-' (and is not exactly "-" or "--")
|
||||||
|
is an option element. The characters of this element
|
||||||
|
(aside from the initial `-') are option characters. If \fBgetopt()\fP
|
||||||
|
is called repeatedly, it returns successively each of the option characters
|
||||||
|
from each of the option elements.
|
||||||
|
.PP
|
||||||
|
If \fBgetopt()\fP finds another option character, it returns that
|
||||||
|
character, updating the external variable \fIoptind\fP and a static
|
||||||
|
variable \fInextchar\fP so that the next call to \fBgetopt()\fP can
|
||||||
|
resume the scan with the following option character or
|
||||||
|
\fIargv\fP-element.
|
||||||
|
.PP
|
||||||
|
If there are no more option characters, \fBgetopt()\fP returns
|
||||||
|
\fBEOF\fP. Then \fIoptind\fP is the index in \fIargv\fP of the first
|
||||||
|
\fIargv\fP-element that is not an option.
|
||||||
|
.PP
|
||||||
|
.I optstring
|
||||||
|
is a string containing the legitimate option characters. If such a
|
||||||
|
character is followed by a colon, the option requires an argument, so
|
||||||
|
\fBgetopt\fP places a pointer to the following text in the same
|
||||||
|
\fIargv\fP-element, or the text of the following \fIargv\fP-element, in
|
||||||
|
.IR optarg .
|
||||||
|
Two colons mean an option takes
|
||||||
|
an optional arg; if there is text in the current \fIargv\fP-element,
|
||||||
|
it is returned in \fIoptarg\fP, otherwise \fIoptarg\fP is set to zero.
|
||||||
|
.PP
|
||||||
|
By default, \fBgetargs()\fP permutes the contents of \fIargv\fP as it
|
||||||
|
scans, so that eventually all the non-options are at the end. Two
|
||||||
|
other modes are also implemented. If the first character of
|
||||||
|
\fIoptstring\fP is `+' or the environment variable POSIXLY_CORRECT is
|
||||||
|
set, then option processing stops as soon as a non-option argument is
|
||||||
|
encountered. If the first character of \fIoptstring\fP is `-', then
|
||||||
|
each non-option \fIargv\fP-element is handled as if it were the argument of
|
||||||
|
an option with character code 1. (This is used by programs that were
|
||||||
|
written to expect options and other \fIargv\fP-elements in any order
|
||||||
|
and that care about the ordering of the two.)
|
||||||
|
The special argument `--' forces an end of option-scanning regardless
|
||||||
|
of the scanning mode.
|
||||||
|
.PP
|
||||||
|
If \fBgetopt()\fP does not recognize an option character, it prints an
|
||||||
|
error message to stderr, stores the character in \fIoptopt\fP, and
|
||||||
|
returns `?'. The calling program may prevent the error message by
|
||||||
|
setting \fIopterr\fP to 0.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.B getopt_long()
|
||||||
|
function works like
|
||||||
|
.B getopt()
|
||||||
|
except that it also accepts long options, started out by two dashes.
|
||||||
|
Long option names may be abbreviated if the abbreviation is
|
||||||
|
unique or is an exact match for some defined option. A long option
|
||||||
|
may take a parameter, of the form
|
||||||
|
.B --arg=param
|
||||||
|
or
|
||||||
|
.BR "--arg param" .
|
||||||
|
.PP
|
||||||
|
.I longopts
|
||||||
|
is a pointer to the first element of an array of
|
||||||
|
.B struct option
|
||||||
|
declared in
|
||||||
|
.B <getopt.h>
|
||||||
|
as
|
||||||
|
.nf
|
||||||
|
.sp
|
||||||
|
.in 10
|
||||||
|
struct option {
|
||||||
|
.in 14
|
||||||
|
const char *name;
|
||||||
|
int has_arg;
|
||||||
|
int *flag;
|
||||||
|
int val;
|
||||||
|
.in 10
|
||||||
|
};
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
The meanings of the different fields are:
|
||||||
|
.TP
|
||||||
|
.I name
|
||||||
|
is the name of the long option.
|
||||||
|
.TP
|
||||||
|
.I has_arg
|
||||||
|
is:
|
||||||
|
\fBno_argument\fP (or 0) if the option does not take an argument,
|
||||||
|
\fBrequired_argument\fP (or 1) if the option requires an argument, or
|
||||||
|
\fBoptional_argument\fP (or 2) if the option takes an optional argument.
|
||||||
|
.TP
|
||||||
|
.I flag
|
||||||
|
specifies how results are returned for a long option. If \fIflag\fP
|
||||||
|
is \fBNULL\fP, then \fBgetopt_long()\fP returns \fIval\fP. (For
|
||||||
|
example, the calling program may set \fIval\fP to the equivalent short
|
||||||
|
option character.) Otherwise, \fBgetopt_long()\fP returns 0, and
|
||||||
|
\fIflag\fP points to a variable which is set to \fIval\fP if the
|
||||||
|
option is found, but left unchanged if the option is not found.
|
||||||
|
.TP
|
||||||
|
\fIval\fP
|
||||||
|
is the value to return, or to load into the variable pointed
|
||||||
|
to by \fIflag\fP.
|
||||||
|
.PP
|
||||||
|
The last element of the array has to be filled with zeroes.
|
||||||
|
.PP
|
||||||
|
If \fIlongindex\fP is not \fBNULL\fP, it
|
||||||
|
points to a variable which is set to the index of the long option relative to
|
||||||
|
.IR longopts .
|
||||||
|
.PP
|
||||||
|
\fBgetopt_long_only()\fP is like \fBgetopt_long()\fP, but `-' as well
|
||||||
|
as `--' can indicate a long option. If an option that starts with `-'
|
||||||
|
(not `--') doesn't match a long option, but does match a short option,
|
||||||
|
it is parsed as a short option instead.
|
||||||
|
.SH "RETURN VALUE"
|
||||||
|
The
|
||||||
|
.B getopt()
|
||||||
|
function returns the option character if the option was found
|
||||||
|
successfully, `:' if there was a missing parameter for one of the
|
||||||
|
options, `?' for an unknown option character, or \fBEOF\fP
|
||||||
|
for the end of the option list.
|
||||||
|
.PP
|
||||||
|
\fBgetopt_long()\fP and \fBgetopt_long_only()\fP also return the option
|
||||||
|
character when a short option is recognized. For a long option, they
|
||||||
|
return \fIval\fP if \fIflag\fP is \fBNULL\fP, and 0 otherwise. Error
|
||||||
|
and EOF returns are the same as for \fBgetopt()\fP, plus `?' for an
|
||||||
|
ambiguous match or an extraneous parameter.
|
||||||
|
.SH "ENVIRONMENT VARIABLES"
|
||||||
|
.TP
|
||||||
|
.SM
|
||||||
|
.B POSIXLY_CORRECT
|
||||||
|
If this is set, then option processing stops as soon as a non-option
|
||||||
|
argument is encountered.
|
||||||
|
.SH "EXAMPLE"
|
||||||
|
The following example program, from the source code, illustrates the
|
||||||
|
use of
|
||||||
|
.BR getopt_long()
|
||||||
|
with most of its features.
|
||||||
|
.nf
|
||||||
|
.sp
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (argc, argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
int digit_optind = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int this_option_optind = optind ? optind : 1;
|
||||||
|
int option_index = 0;
|
||||||
|
static struct option long_options[] =
|
||||||
|
{
|
||||||
|
{"add", 1, 0, 0},
|
||||||
|
{"append", 0, 0, 0},
|
||||||
|
{"delete", 1, 0, 0},
|
||||||
|
{"verbose", 0, 0, 0},
|
||||||
|
{"create", 1, 0, 'c'},
|
||||||
|
{"file", 1, 0, 0},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
c = getopt_long (argc, argv, "abc:d:012",
|
||||||
|
long_options, &option_index);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
printf ("option %s", long_options[option_index].name);
|
||||||
|
if (optarg)
|
||||||
|
printf (" with arg %s", optarg);
|
||||||
|
printf ("\\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||||
|
printf ("digits occur in two different argv-elements.\\n");
|
||||||
|
digit_optind = this_option_optind;
|
||||||
|
printf ("option %c\\n", c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
printf ("option a\\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
printf ("option b\\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
printf ("option c with value `%s'\\n", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
printf ("option d with value `%s'\\n", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf ("?? getopt returned character code 0%o ??\\n", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
printf ("non-option ARGV-elements: ");
|
||||||
|
while (optind < argc)
|
||||||
|
printf ("%s ", argv[optind++]);
|
||||||
|
printf ("\\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH "BUGS"
|
||||||
|
This manpage is confusing.
|
||||||
|
.SH "CONFORMING TO"
|
||||||
|
.TP
|
||||||
|
\fBgetopt()\fP:
|
||||||
|
POSIX.1, provided the environment variable POSIXLY_CORRECT is set.
|
||||||
|
Otherwise, the elements of \fIargv\fP aren't really const, because we
|
||||||
|
permute them. We pretend they're const in the prototype to be
|
||||||
|
compatible with other systems.
|
||||||
|
|
||||||
56
common/win/my_getopt-1.5/getopt.h
Normal file
56
common/win/my_getopt-1.5/getopt.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* getopt.h - cpp wrapper for my_getopt to make it look like getopt.
|
||||||
|
* Copyright 1997, 2000, 2001, 2002, Benjamin Sittler
|
||||||
|
*
|
||||||
|
* 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 shall 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MY_WRAPPER_GETOPT_H_INCLUDED
|
||||||
|
#define MY_WRAPPER_GETOPT_H_INCLUDED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "my_getopt.h"
|
||||||
|
|
||||||
|
#undef getopt
|
||||||
|
#define getopt my_getopt
|
||||||
|
#undef getopt_long
|
||||||
|
#define getopt_long my_getopt_long
|
||||||
|
#undef getopt_long_only
|
||||||
|
#define getopt_long_only my_getopt_long_only
|
||||||
|
#undef _getopt_internal
|
||||||
|
#define _getopt_internal _my_getopt_internal
|
||||||
|
#undef opterr
|
||||||
|
#define opterr my_opterr
|
||||||
|
#undef optind
|
||||||
|
#define optind my_optind
|
||||||
|
#undef optopt
|
||||||
|
#define optopt my_optopt
|
||||||
|
#undef optarg
|
||||||
|
#define optarg my_optarg
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MY_WRAPPER_GETOPT_H_INCLUDED */
|
||||||
330
common/win/my_getopt-1.5/getopt.txt
Normal file
330
common/win/my_getopt-1.5/getopt.txt
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
||||||
|
|
||||||
|
|
||||||
|
NAME
|
||||||
|
getopt - Parse command line options
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int getopt(int argc, char * const argv[],
|
||||||
|
const char *optstring);
|
||||||
|
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind, opterr, optopt;
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
int getopt_long(int argc, char * const argv[],
|
||||||
|
const char *optstring,
|
||||||
|
const struct option *longopts, int *longindex);
|
||||||
|
|
||||||
|
int getopt_long_only(int argc, char * const argv[],
|
||||||
|
const char *optstring,
|
||||||
|
const struct option *longopts, int *longindex);
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The getopt() function parses the command line arguments.
|
||||||
|
Its arguments argc and argv are the argument count and
|
||||||
|
array as passed to the main() function on program invoca-
|
||||||
|
tion. An element of argv that starts with `-' (and is not
|
||||||
|
exactly "-" or "--") is an option element. The characters
|
||||||
|
of this element (aside from the initial `-') are option
|
||||||
|
characters. If getopt() is called repeatedly, it returns
|
||||||
|
successively each of the option characters from each of
|
||||||
|
the option elements.
|
||||||
|
|
||||||
|
If getopt() finds another option character, it returns
|
||||||
|
that character, updating the external variable optind and
|
||||||
|
a static variable nextchar so that the next call to
|
||||||
|
getopt() can resume the scan with the following option
|
||||||
|
character or argv-element.
|
||||||
|
|
||||||
|
If there are no more option characters, getopt() returns
|
||||||
|
EOF. Then optind is the index in argv of the first argv-
|
||||||
|
element that is not an option.
|
||||||
|
|
||||||
|
optstring is a string containing the legitimate option
|
||||||
|
characters. If such a character is followed by a colon,
|
||||||
|
the option requires an argument, so getopt places a
|
||||||
|
pointer to the following text in the same argv-element, or
|
||||||
|
the text of the following argv-element, in optarg. Two
|
||||||
|
colons mean an option takes an optional arg; if there is
|
||||||
|
text in the current argv-element, it is returned in
|
||||||
|
optarg, otherwise optarg is set to zero.
|
||||||
|
|
||||||
|
By default, getargs() permutes the contents of argv as it
|
||||||
|
scans, so that eventually all the non-options are at the
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GNU Aug 30, 1995 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
||||||
|
|
||||||
|
|
||||||
|
end. Two other modes are also implemented. If the first
|
||||||
|
character of optstring is `+' or the environment variable
|
||||||
|
POSIXLY_CORRECT is set, then option processing stops as
|
||||||
|
soon as a non-option argument is encountered. If the
|
||||||
|
first character of optstring is `-', then each non-option
|
||||||
|
argv-element is handled as if it were the argument of an
|
||||||
|
option with character code 1. (This is used by programs
|
||||||
|
that were written to expect options and other argv-ele-
|
||||||
|
ments in any order and that care about the ordering of the
|
||||||
|
two.) The special argument `--' forces an end of option-
|
||||||
|
scanning regardless of the scanning mode.
|
||||||
|
|
||||||
|
If getopt() does not recognize an option character, it
|
||||||
|
prints an error message to stderr, stores the character in
|
||||||
|
optopt, and returns `?'. The calling program may prevent
|
||||||
|
the error message by setting opterr to 0.
|
||||||
|
|
||||||
|
The getopt_long() function works like getopt() except that
|
||||||
|
it also accepts long options, started out by two dashes.
|
||||||
|
Long option names may be abbreviated if the abbreviation
|
||||||
|
is unique or is an exact match for some defined option. A
|
||||||
|
long option may take a parameter, of the form --arg=param
|
||||||
|
or --arg param.
|
||||||
|
|
||||||
|
longopts is a pointer to the first element of an array of
|
||||||
|
struct option declared in <getopt.h> as
|
||||||
|
|
||||||
|
struct option {
|
||||||
|
const char *name;
|
||||||
|
int has_arg;
|
||||||
|
int *flag;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
The meanings of the different fields are:
|
||||||
|
|
||||||
|
name is the name of the long option.
|
||||||
|
|
||||||
|
has_arg
|
||||||
|
is: no_argument (or 0) if the option does not take
|
||||||
|
an argument, required_argument (or 1) if the option
|
||||||
|
requires an argument, or optional_argument (or 2)
|
||||||
|
if the option takes an optional argument.
|
||||||
|
|
||||||
|
flag specifies how results are returned for a long
|
||||||
|
option. If flag is NULL, then getopt_long()
|
||||||
|
returns val. (For example, the calling program may
|
||||||
|
set val to the equivalent short option character.)
|
||||||
|
Otherwise, getopt_long() returns 0, and flag points
|
||||||
|
to a variable which is set to val if the option is
|
||||||
|
found, but left unchanged if the option is not
|
||||||
|
found.
|
||||||
|
|
||||||
|
val is the value to return, or to load into the
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GNU Aug 30, 1995 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
||||||
|
|
||||||
|
|
||||||
|
variable pointed to by flag.
|
||||||
|
|
||||||
|
The last element of the array has to be filled with
|
||||||
|
zeroes.
|
||||||
|
|
||||||
|
If longindex is not NULL, it points to a variable which is
|
||||||
|
set to the index of the long option relative to longopts.
|
||||||
|
|
||||||
|
getopt_long_only() is like getopt_long(), but `-' as well
|
||||||
|
as `--' can indicate a long option. If an option that
|
||||||
|
starts with `-' (not `--') doesn't match a long option,
|
||||||
|
but does match a short option, it is parsed as a short
|
||||||
|
option instead.
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
The getopt() function returns the option character if the
|
||||||
|
option was found successfully, `:' if there was a missing
|
||||||
|
parameter for one of the options, `?' for an unknown
|
||||||
|
option character, or EOF for the end of the option list.
|
||||||
|
|
||||||
|
getopt_long() and getopt_long_only() also return the
|
||||||
|
option character when a short option is recognized. For a
|
||||||
|
long option, they return val if flag is NULL, and 0 other-
|
||||||
|
wise. Error and EOF returns are the same as for getopt(),
|
||||||
|
plus `?' for an ambiguous match or an extraneous parame-
|
||||||
|
ter.
|
||||||
|
|
||||||
|
ENVIRONMENT VARIABLES
|
||||||
|
POSIXLY_CORRECT
|
||||||
|
If this is set, then option processing stops as
|
||||||
|
soon as a non-option argument is encountered.
|
||||||
|
|
||||||
|
EXAMPLE
|
||||||
|
The following example program, from the source code,
|
||||||
|
illustrates the use of getopt_long() with most of its fea-
|
||||||
|
tures.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (argc, argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
int digit_optind = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int this_option_optind = optind ? optind : 1;
|
||||||
|
int option_index = 0;
|
||||||
|
static struct option long_options[] =
|
||||||
|
{
|
||||||
|
{"add", 1, 0, 0},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GNU Aug 30, 1995 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
||||||
|
|
||||||
|
|
||||||
|
{"append", 0, 0, 0},
|
||||||
|
{"delete", 1, 0, 0},
|
||||||
|
{"verbose", 0, 0, 0},
|
||||||
|
{"create", 1, 0, 'c'},
|
||||||
|
{"file", 1, 0, 0},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
c = getopt_long (argc, argv, "abc:d:012",
|
||||||
|
long_options, &option_index);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
printf ("option %s", long_options[option_index].name);
|
||||||
|
if (optarg)
|
||||||
|
printf (" with arg %s", optarg);
|
||||||
|
printf ("\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||||
|
printf ("digits occur in two different argv-elements.\n");
|
||||||
|
digit_optind = this_option_optind;
|
||||||
|
printf ("option %c\n", c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
printf ("option a\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
printf ("option b\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
printf ("option c with value `%s'\n", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
printf ("option d with value `%s'\n", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GNU Aug 30, 1995 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
||||||
|
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
printf ("non-option ARGV-elements: ");
|
||||||
|
while (optind < argc)
|
||||||
|
printf ("%s ", argv[optind++]);
|
||||||
|
printf ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BUGS
|
||||||
|
This manpage is confusing.
|
||||||
|
|
||||||
|
CONFORMING TO
|
||||||
|
getopt():
|
||||||
|
POSIX.1, provided the environment variable
|
||||||
|
POSIXLY_CORRECT is set. Otherwise, the elements of
|
||||||
|
argv aren't really const, because we permute them.
|
||||||
|
We pretend they're const in the prototype to be
|
||||||
|
compatible with other systems.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GNU Aug 30, 1995 5
|
||||||
|
|
||||||
|
|
||||||
387
common/win/my_getopt-1.5/main.c
Normal file
387
common/win/my_getopt-1.5/main.c
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
/*
|
||||||
|
* copy - test program for my getopt() re-implementation
|
||||||
|
*
|
||||||
|
* This program is in the public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VERSION \
|
||||||
|
"0.3"
|
||||||
|
|
||||||
|
#define COPYRIGHT \
|
||||||
|
"This program is in the public domain."
|
||||||
|
|
||||||
|
/* for isprint(), printf(), fopen(), perror(), getenv(), strcmp(), etc. */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* for my getopt() re-implementation */
|
||||||
|
#include "getopt.h"
|
||||||
|
|
||||||
|
/* the default verbosity level is 0 (no verbose reporting) */
|
||||||
|
static unsigned verbose = 0;
|
||||||
|
|
||||||
|
/* print version and copyright information */
|
||||||
|
static void
|
||||||
|
version(char *progname)
|
||||||
|
{
|
||||||
|
printf("%s version %s\n"
|
||||||
|
"%s\n",
|
||||||
|
progname,
|
||||||
|
VERSION,
|
||||||
|
COPYRIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print a help summary */
|
||||||
|
static void
|
||||||
|
help(char *progname)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [options] [FILE]...\n"
|
||||||
|
"Options:\n"
|
||||||
|
"-h or -help show this message and exit\n"
|
||||||
|
"-append append to the output file\n"
|
||||||
|
"-o FILE or\n"
|
||||||
|
"-output FILE send output to FILE (default is stdout)\n"
|
||||||
|
"-r or --rotate rotate letters 13 positions (rot13)\n"
|
||||||
|
"-rNUM or\n"
|
||||||
|
"--rotate=NUM rotate letters NUM positions\n"
|
||||||
|
"-truncate truncate the output file "
|
||||||
|
"(this is the default)\n"
|
||||||
|
"-v or -verbose increase the level of verbosity by 1"
|
||||||
|
"(the default is 0)\n"
|
||||||
|
"-vNUM or\n"
|
||||||
|
"-verbose=NUM set the level of verbosity to NUM\n"
|
||||||
|
"-V or -version print program version and exit\n"
|
||||||
|
"\n"
|
||||||
|
"This program reads the specified FILEs "
|
||||||
|
"(or stdin if none are given)\n"
|
||||||
|
"and writes their bytes to the specified output FILE "
|
||||||
|
"(or stdout if none is\n"
|
||||||
|
"given.) It can optionally rotate letters.\n",
|
||||||
|
progname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print usage information to stderr */
|
||||||
|
static void
|
||||||
|
usage(char *progname)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Summary: %s [-help] [-version] [options] [FILE]...\n",
|
||||||
|
progname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* input file handler -- returns nonzero or exit()s on failure */
|
||||||
|
static int
|
||||||
|
handle(char *progname,
|
||||||
|
FILE *infile, char *infilename,
|
||||||
|
FILE *outfile, char *outfilename,
|
||||||
|
int rotate)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
unsigned long bytes_copied = 0;
|
||||||
|
|
||||||
|
if (verbose > 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: copying from `%s' to `%s'\n",
|
||||||
|
progname,
|
||||||
|
infilename,
|
||||||
|
outfilename);
|
||||||
|
}
|
||||||
|
while ((c = getc(infile)) != EOF)
|
||||||
|
{
|
||||||
|
if (rotate && isalpha(c))
|
||||||
|
{
|
||||||
|
const char *letters = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
char *match;
|
||||||
|
if ((match = strchr(letters, tolower(c))))
|
||||||
|
{
|
||||||
|
char rc = letters[(match - letters + rotate) % 26];
|
||||||
|
if (isupper(c))
|
||||||
|
rc = toupper(rc);
|
||||||
|
c = rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (putc(c, outfile) == EOF)
|
||||||
|
{
|
||||||
|
perror(outfilename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
bytes_copied ++;
|
||||||
|
}
|
||||||
|
if (! feof(infile))
|
||||||
|
{
|
||||||
|
perror(infilename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (verbose > 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: %lu bytes copied from `%s' to `%s'\n",
|
||||||
|
progname,
|
||||||
|
bytes_copied,
|
||||||
|
infilename,
|
||||||
|
outfilename);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* argument parser and dispatcher */
|
||||||
|
int
|
||||||
|
main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
/* the program name */
|
||||||
|
char *progname = argv[0];
|
||||||
|
/* during argument parsing, opt contains the return value from getopt() */
|
||||||
|
int opt;
|
||||||
|
/* the output filename is initially 0 (a.k.a. stdout) */
|
||||||
|
char *outfilename = 0;
|
||||||
|
/* the default return value is initially 0 (success) */
|
||||||
|
int retval = 0;
|
||||||
|
/* initially we truncate */
|
||||||
|
int append = 0;
|
||||||
|
/* initially we don't rotate letters */
|
||||||
|
int rotate = 0;
|
||||||
|
|
||||||
|
/* short options string */
|
||||||
|
char *shortopts = "Vho:r::v::";
|
||||||
|
/* long options list */
|
||||||
|
struct option longopts[] =
|
||||||
|
{
|
||||||
|
/* name, has_arg, flag, val */ /* longind */
|
||||||
|
{ "append", no_argument, 0, 0 }, /* 0 */
|
||||||
|
{ "truncate", no_argument, 0, 0 }, /* 1 */
|
||||||
|
{ "version", no_argument, 0, 'V' }, /* 3 */
|
||||||
|
{ "help", no_argument, 0, 'h' }, /* 4 */
|
||||||
|
{ "output", required_argument, 0, 'o' }, /* 5 */
|
||||||
|
{ "rotate", optional_argument, 0, 'r' }, /* 6 */
|
||||||
|
{ "verbose", optional_argument, 0, 'v' }, /* 7 */
|
||||||
|
/* end-of-list marker */
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
/* long option list index */
|
||||||
|
int longind = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print a warning when the POSIXLY_CORRECT environment variable will
|
||||||
|
* interfere with argument placement
|
||||||
|
*/
|
||||||
|
if (getenv("POSIXLY_CORRECT"))
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: "
|
||||||
|
"Warning: implicit argument reordering disallowed by "
|
||||||
|
"POSIXLY_CORRECT\n",
|
||||||
|
progname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse all options from the command line */
|
||||||
|
while ((opt =
|
||||||
|
getopt_long_only(argc, argv, shortopts, longopts, &longind)) != -1)
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
case 0: /* a long option without an equivalent short option */
|
||||||
|
switch (longind)
|
||||||
|
{
|
||||||
|
case 0: /* -append */
|
||||||
|
append = 1;
|
||||||
|
break;
|
||||||
|
case 1: /* -truncate */
|
||||||
|
append = 0;
|
||||||
|
break;
|
||||||
|
default: /* something unexpected has happened */
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: "
|
||||||
|
"getopt_long_only unexpectedly returned %d for `--%s'\n",
|
||||||
|
progname,
|
||||||
|
opt,
|
||||||
|
longopts[longind].name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'V': /* -version */
|
||||||
|
version(progname);
|
||||||
|
return 0;
|
||||||
|
case 'h': /* -help */
|
||||||
|
help(progname);
|
||||||
|
return 0;
|
||||||
|
case 'r': /* -rotate[=NUM] */
|
||||||
|
if (optarg)
|
||||||
|
{
|
||||||
|
/* we use this while trying to parse a numeric argument */
|
||||||
|
char ignored;
|
||||||
|
if (sscanf(optarg,
|
||||||
|
"%d%c",
|
||||||
|
&rotate,
|
||||||
|
&ignored) != 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: "
|
||||||
|
"rotation `%s' is not a number\n",
|
||||||
|
progname,
|
||||||
|
optarg);
|
||||||
|
usage(progname);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
/* normalize rotation */
|
||||||
|
while (rotate < 0)
|
||||||
|
{
|
||||||
|
rotate += 26;
|
||||||
|
}
|
||||||
|
rotate %= 26;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rotate = 13;
|
||||||
|
break;
|
||||||
|
case 'o': /* -output=FILE */
|
||||||
|
outfilename = optarg;
|
||||||
|
/* we allow "-" as a synonym for stdout here */
|
||||||
|
if (! strcmp(optarg, "-"))
|
||||||
|
{
|
||||||
|
outfilename = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'v': /* -verbose[=NUM] */
|
||||||
|
if (optarg)
|
||||||
|
{
|
||||||
|
/* we use this while trying to parse a numeric argument */
|
||||||
|
char ignored;
|
||||||
|
if (sscanf(optarg,
|
||||||
|
"%u%c",
|
||||||
|
&verbose,
|
||||||
|
&ignored) != 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: "
|
||||||
|
"verbosity level `%s' is not a number\n",
|
||||||
|
progname,
|
||||||
|
optarg);
|
||||||
|
usage(progname);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
verbose ++;
|
||||||
|
break;
|
||||||
|
case '?': /* getopt_long_only noticed an error */
|
||||||
|
usage(progname);
|
||||||
|
return 2;
|
||||||
|
default: /* something unexpected has happened */
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: "
|
||||||
|
"getopt_long_only returned an unexpected value (%d)\n",
|
||||||
|
progname,
|
||||||
|
opt);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-open stdout to outfilename, if requested */
|
||||||
|
if (outfilename)
|
||||||
|
{
|
||||||
|
if (! freopen(outfilename, (append ? "a" : "w"), stdout))
|
||||||
|
{
|
||||||
|
perror(outfilename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* make a human-readable version of the output filename "-" */
|
||||||
|
outfilename = "stdout";
|
||||||
|
/* you can't truncate stdout */
|
||||||
|
append = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: verbosity level is %u; %s `%s'; rotation %d\n",
|
||||||
|
progname,
|
||||||
|
verbose,
|
||||||
|
(append ? "appending to" : "truncating"),
|
||||||
|
outfilename,
|
||||||
|
rotate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose > 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: %d input file(s) were given\n",
|
||||||
|
progname,
|
||||||
|
((argc > optind) ? (argc - optind) : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose > 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"\topterr: %d\n\toptind: %d\n\toptopt: %d (%c)\n\toptarg: %s\n",
|
||||||
|
opterr,
|
||||||
|
optind,
|
||||||
|
optopt, optopt,
|
||||||
|
optarg ? optarg : "(null)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle each of the input files (or stdin, if no files were given) */
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
int argindex;
|
||||||
|
|
||||||
|
for (argindex = optind; argindex < argc; argindex ++)
|
||||||
|
{
|
||||||
|
char *infilename = argv[argindex];
|
||||||
|
FILE *infile;
|
||||||
|
|
||||||
|
/* we allow "-" as a synonym for stdin here */
|
||||||
|
if (! strcmp(infilename, "-"))
|
||||||
|
{
|
||||||
|
infile = stdin;
|
||||||
|
infilename = "stdin";
|
||||||
|
}
|
||||||
|
else if (! (infile = fopen(infilename, "r")))
|
||||||
|
{
|
||||||
|
perror(infilename);
|
||||||
|
retval = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (handle(progname,
|
||||||
|
infile, argv[optind],
|
||||||
|
stdout, outfilename,
|
||||||
|
rotate))
|
||||||
|
{
|
||||||
|
retval = 1;
|
||||||
|
fclose(infile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((infile != stdin) && fclose(infile))
|
||||||
|
{
|
||||||
|
perror(infilename);
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval =
|
||||||
|
handle(progname,
|
||||||
|
stdin, "stdin",
|
||||||
|
stdout, outfilename,
|
||||||
|
rotate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close stdout */
|
||||||
|
if (fclose(stdout))
|
||||||
|
{
|
||||||
|
perror(outfilename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose > 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: normal return, exit code is %d\n",
|
||||||
|
progname,
|
||||||
|
retval);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
281
common/win/my_getopt-1.5/my_getopt.c
Normal file
281
common/win/my_getopt-1.5/my_getopt.c
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
/*
|
||||||
|
* my_getopt.c - my re-implementation of getopt.
|
||||||
|
* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
|
||||||
|
*
|
||||||
|
* 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 shall 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "my_getopt.h"
|
||||||
|
|
||||||
|
int my_optind=1, my_opterr=1, my_optopt=0;
|
||||||
|
char *my_optarg=0;
|
||||||
|
|
||||||
|
/* reset argument parser to start-up values */
|
||||||
|
int my_getopt_reset(void)
|
||||||
|
{
|
||||||
|
my_optind = 1;
|
||||||
|
my_opterr = 1;
|
||||||
|
my_optopt = 0;
|
||||||
|
my_optarg = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is the plain old UNIX getopt, with GNU-style extensions. */
|
||||||
|
/* if you're porting some piece of UNIX software, this is all you need. */
|
||||||
|
/* this supports GNU-style permution and optional arguments */
|
||||||
|
|
||||||
|
int my_getopt(int argc, char * argv[], const char *opts)
|
||||||
|
{
|
||||||
|
static int charind=0;
|
||||||
|
char mode, colon_mode;
|
||||||
|
int off = 0, opt = -1;
|
||||||
|
|
||||||
|
if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
|
||||||
|
else {
|
||||||
|
if((colon_mode = *opts) == ':') off ++;
|
||||||
|
if(((mode = opts[off]) == '+') || (mode == '-')) {
|
||||||
|
off++;
|
||||||
|
if((colon_mode != ':') && ((colon_mode = opts[off]) == ':'))
|
||||||
|
off ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my_optarg = 0;
|
||||||
|
if(charind) {
|
||||||
|
const char *s;
|
||||||
|
my_optopt = argv[my_optind][charind];
|
||||||
|
for(s=opts+off; *s; s++) if(my_optopt == *s) {
|
||||||
|
charind++;
|
||||||
|
if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) {
|
||||||
|
if(argv[my_optind][charind]) {
|
||||||
|
my_optarg = &(argv[my_optind++][charind]);
|
||||||
|
charind = 0;
|
||||||
|
} else if(*(++s) != ':') {
|
||||||
|
charind = 0;
|
||||||
|
if(++my_optind >= argc) {
|
||||||
|
if(my_opterr) fprintf(stderr,
|
||||||
|
"%s: option requires an argument -- %c\n",
|
||||||
|
argv[0], my_optopt);
|
||||||
|
opt = (colon_mode == ':') ? ':' : '?';
|
||||||
|
goto my_getopt_ok;
|
||||||
|
}
|
||||||
|
my_optarg = argv[my_optind++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opt = my_optopt;
|
||||||
|
goto my_getopt_ok;
|
||||||
|
}
|
||||||
|
if(my_opterr) fprintf(stderr,
|
||||||
|
"%s: illegal option -- %c\n",
|
||||||
|
argv[0], my_optopt);
|
||||||
|
opt = '?';
|
||||||
|
if(argv[my_optind][++charind] == '\0') {
|
||||||
|
my_optind++;
|
||||||
|
charind = 0;
|
||||||
|
}
|
||||||
|
my_getopt_ok:
|
||||||
|
if(charind && ! argv[my_optind][charind]) {
|
||||||
|
my_optind++;
|
||||||
|
charind = 0;
|
||||||
|
}
|
||||||
|
} else if((my_optind >= argc) ||
|
||||||
|
((argv[my_optind][0] == '-') &&
|
||||||
|
(argv[my_optind][1] == '-') &&
|
||||||
|
(argv[my_optind][2] == '\0'))) {
|
||||||
|
my_optind++;
|
||||||
|
opt = -1;
|
||||||
|
} else if((argv[my_optind][0] != '-') ||
|
||||||
|
(argv[my_optind][1] == '\0')) {
|
||||||
|
char *tmp;
|
||||||
|
int i, j, k;
|
||||||
|
|
||||||
|
if(mode == '+') opt = -1;
|
||||||
|
else if(mode == '-') {
|
||||||
|
my_optarg = argv[my_optind++];
|
||||||
|
charind = 0;
|
||||||
|
opt = 1;
|
||||||
|
} else {
|
||||||
|
for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
|
||||||
|
(argv[i][1] != '\0')) {
|
||||||
|
my_optind=i;
|
||||||
|
opt=my_getopt(argc, argv, opts);
|
||||||
|
while(i > j) {
|
||||||
|
tmp=argv[--i];
|
||||||
|
for(k=i; k+1<my_optind; k++) argv[k]=argv[k+1];
|
||||||
|
argv[--my_optind]=tmp;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(i == argc) opt = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
charind++;
|
||||||
|
opt = my_getopt(argc, argv, opts);
|
||||||
|
}
|
||||||
|
if (my_optind > argc) my_optind = argc;
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is the extended getopt_long{,_only}, with some GNU-like
|
||||||
|
* extensions. Implements _getopt_internal in case any programs
|
||||||
|
* expecting GNU libc getopt call it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int _my_getopt_internal(int argc, char * argv[], const char *shortopts,
|
||||||
|
const struct option *longopts, int *longind,
|
||||||
|
int long_only)
|
||||||
|
{
|
||||||
|
char mode, colon_mode = *shortopts;
|
||||||
|
int shortoff = 0, opt = -1;
|
||||||
|
|
||||||
|
if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
|
||||||
|
else {
|
||||||
|
if((colon_mode = *shortopts) == ':') shortoff ++;
|
||||||
|
if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) {
|
||||||
|
shortoff++;
|
||||||
|
if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':'))
|
||||||
|
shortoff ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my_optarg = 0;
|
||||||
|
if((my_optind >= argc) ||
|
||||||
|
((argv[my_optind][0] == '-') &&
|
||||||
|
(argv[my_optind][1] == '-') &&
|
||||||
|
(argv[my_optind][2] == '\0'))) {
|
||||||
|
my_optind++;
|
||||||
|
opt = -1;
|
||||||
|
} else if((argv[my_optind][0] != '-') ||
|
||||||
|
(argv[my_optind][1] == '\0')) {
|
||||||
|
char *tmp;
|
||||||
|
int i, j, k;
|
||||||
|
|
||||||
|
opt = -1;
|
||||||
|
if(mode == '+') return -1;
|
||||||
|
else if(mode == '-') {
|
||||||
|
my_optarg = argv[my_optind++];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
|
||||||
|
(argv[i][1] != '\0')) {
|
||||||
|
my_optind=i;
|
||||||
|
opt=_my_getopt_internal(argc, argv, shortopts,
|
||||||
|
longopts, longind,
|
||||||
|
long_only);
|
||||||
|
while(i > j) {
|
||||||
|
tmp=argv[--i];
|
||||||
|
for(k=i; k+1<my_optind; k++)
|
||||||
|
argv[k]=argv[k+1];
|
||||||
|
argv[--my_optind]=tmp;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if((!long_only) && (argv[my_optind][1] != '-'))
|
||||||
|
opt = my_getopt(argc, argv, shortopts);
|
||||||
|
else {
|
||||||
|
int charind, offset;
|
||||||
|
int found = 0, ind, hits = 0;
|
||||||
|
|
||||||
|
if(((my_optopt = argv[my_optind][1]) != '-') && ! argv[my_optind][2]) {
|
||||||
|
int c;
|
||||||
|
|
||||||
|
ind = shortoff;
|
||||||
|
while((c = shortopts[ind++])) {
|
||||||
|
if(((shortopts[ind] == ':') ||
|
||||||
|
((c == 'W') && (shortopts[ind] == ';'))) &&
|
||||||
|
(shortopts[++ind] == ':'))
|
||||||
|
ind ++;
|
||||||
|
if(my_optopt == c) return my_getopt(argc, argv, shortopts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset = 2 - (argv[my_optind][1] != '-');
|
||||||
|
for(charind = offset;
|
||||||
|
(argv[my_optind][charind] != '\0') &&
|
||||||
|
(argv[my_optind][charind] != '=');
|
||||||
|
charind++);
|
||||||
|
for(ind = 0; longopts[ind].name && !hits; ind++)
|
||||||
|
if((strlen(longopts[ind].name) == (size_t) (charind - offset)) &&
|
||||||
|
(strncmp(longopts[ind].name,
|
||||||
|
argv[my_optind] + offset, charind - offset) == 0))
|
||||||
|
found = ind, hits++;
|
||||||
|
if(!hits) for(ind = 0; longopts[ind].name; ind++)
|
||||||
|
if(strncmp(longopts[ind].name,
|
||||||
|
argv[my_optind] + offset, charind - offset) == 0)
|
||||||
|
found = ind, hits++;
|
||||||
|
if(hits == 1) {
|
||||||
|
opt = 0;
|
||||||
|
|
||||||
|
if(argv[my_optind][charind] == '=') {
|
||||||
|
if(longopts[found].has_arg == 0) {
|
||||||
|
opt = '?';
|
||||||
|
if(my_opterr) fprintf(stderr,
|
||||||
|
"%s: option `--%s' doesn't allow an argument\n",
|
||||||
|
argv[0], longopts[found].name);
|
||||||
|
} else {
|
||||||
|
my_optarg = argv[my_optind] + ++charind;
|
||||||
|
charind = 0;
|
||||||
|
}
|
||||||
|
} else if(longopts[found].has_arg == 1) {
|
||||||
|
if(++my_optind >= argc) {
|
||||||
|
opt = (colon_mode == ':') ? ':' : '?';
|
||||||
|
if(my_opterr) fprintf(stderr,
|
||||||
|
"%s: option `--%s' requires an argument\n",
|
||||||
|
argv[0], longopts[found].name);
|
||||||
|
} else my_optarg = argv[my_optind];
|
||||||
|
}
|
||||||
|
if(!opt) {
|
||||||
|
if (longind) *longind = found;
|
||||||
|
if(!longopts[found].flag) opt = longopts[found].val;
|
||||||
|
else *(longopts[found].flag) = longopts[found].val;
|
||||||
|
}
|
||||||
|
my_optind++;
|
||||||
|
} else if(!hits) {
|
||||||
|
if(offset == 1) opt = my_getopt(argc, argv, shortopts);
|
||||||
|
else {
|
||||||
|
opt = '?';
|
||||||
|
if(my_opterr) fprintf(stderr,
|
||||||
|
"%s: unrecognized option `%s'\n",
|
||||||
|
argv[0], argv[my_optind++]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opt = '?';
|
||||||
|
if(my_opterr) fprintf(stderr,
|
||||||
|
"%s: option `%s' is ambiguous\n",
|
||||||
|
argv[0], argv[my_optind++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (my_optind > argc) my_optind = argc;
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int my_getopt_long(int argc, char * argv[], const char *shortopts,
|
||||||
|
const struct option *longopts, int *longind)
|
||||||
|
{
|
||||||
|
return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int my_getopt_long_only(int argc, char * argv[], const char *shortopts,
|
||||||
|
const struct option *longopts, int *longind)
|
||||||
|
{
|
||||||
|
return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1);
|
||||||
|
}
|
||||||
72
common/win/my_getopt-1.5/my_getopt.h
Normal file
72
common/win/my_getopt-1.5/my_getopt.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* my_getopt.h - interface to my re-implementation of getopt.
|
||||||
|
* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
|
||||||
|
*
|
||||||
|
* 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 shall 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MY_GETOPT_H_INCLUDED
|
||||||
|
#define MY_GETOPT_H_INCLUDED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* reset argument parser to start-up values */
|
||||||
|
extern int my_getopt_reset(void);
|
||||||
|
|
||||||
|
/* UNIX-style short-argument parser */
|
||||||
|
extern int my_getopt(int argc, char * argv[], const char *opts);
|
||||||
|
|
||||||
|
extern int my_optind, my_opterr, my_optopt;
|
||||||
|
extern char *my_optarg;
|
||||||
|
|
||||||
|
struct option {
|
||||||
|
const char *name;
|
||||||
|
int has_arg;
|
||||||
|
int *flag;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* human-readable values for has_arg */
|
||||||
|
#undef no_argument
|
||||||
|
#define no_argument 0
|
||||||
|
#undef required_argument
|
||||||
|
#define required_argument 1
|
||||||
|
#undef optional_argument
|
||||||
|
#define optional_argument 2
|
||||||
|
|
||||||
|
/* GNU-style long-argument parsers */
|
||||||
|
extern int my_getopt_long(int argc, char * argv[], const char *shortopts,
|
||||||
|
const struct option *longopts, int *longind);
|
||||||
|
|
||||||
|
extern int my_getopt_long_only(int argc, char * argv[], const char *shortopts,
|
||||||
|
const struct option *longopts, int *longind);
|
||||||
|
|
||||||
|
extern int _my_getopt_internal(int argc, char * argv[], const char *shortopts,
|
||||||
|
const struct option *longopts, int *longind,
|
||||||
|
int long_only);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MY_GETOPT_H_INCLUDED */
|
||||||
81
configure.ac
81
configure.ac
@ -1,81 +0,0 @@
|
|||||||
AC_PREREQ([2.63])
|
|
||||||
|
|
||||||
AC_INIT([spice-common],
|
|
||||||
[noversion],
|
|
||||||
[spice-devel@lists.freedesktop.org])
|
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([common/log.h])
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
|
||||||
AM_CONFIG_HEADER([config.h])
|
|
||||||
AC_CONFIG_AUX_DIR([build-aux])
|
|
||||||
|
|
||||||
# For automake >= 1.12
|
|
||||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
|
||||||
|
|
||||||
# Checks for programs
|
|
||||||
AM_INIT_AUTOMAKE([1.11 dist-xz no-dist-gzip tar-ustar foreign subdir-objects -Wall -Werror])
|
|
||||||
AM_MAINTAINER_MODE
|
|
||||||
AM_SILENT_RULES([yes])
|
|
||||||
LT_INIT
|
|
||||||
SPICE_MANUAL
|
|
||||||
|
|
||||||
AC_PROG_CC
|
|
||||||
AC_PROG_CC_C99
|
|
||||||
if test "x$ac_cv_prog_cc_c99" = xno; then
|
|
||||||
AC_MSG_ERROR([C99 compiler is required.])
|
|
||||||
fi
|
|
||||||
AM_PROG_CC_C_O
|
|
||||||
|
|
||||||
AC_CHECK_HEADERS([sys/mman.h regex.h])
|
|
||||||
AC_CHECK_FUNCS([sigaction drand48 setlinebuf])
|
|
||||||
AC_SEARCH_LIBS(regcomp, [regex rx])
|
|
||||||
|
|
||||||
SPICE_CHECK_SYSDEPS
|
|
||||||
SPICE_EXTRA_CHECKS
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([tests],
|
|
||||||
AS_HELP_STRING([--enable-tests],
|
|
||||||
[Enable tests @<:@default=yes@:>@]),
|
|
||||||
[],
|
|
||||||
enable_tests="yes")
|
|
||||||
AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "xyes")
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([alignment-checks],
|
|
||||||
AS_HELP_STRING([--enable-alignment-checks],
|
|
||||||
[Enable runtime checks for cast alignment @<:@default=no@:>@]),
|
|
||||||
[],
|
|
||||||
enable_alignment_checks="no")
|
|
||||||
AS_IF([test "x$enable_alignment_checks" = "xyes"],
|
|
||||||
[AC_DEFINE([SPICE_DEBUG_ALIGNMENT], 1, [Enable runtime checks for cast alignment])])
|
|
||||||
|
|
||||||
SPICE_CHECK_INSTRUMENTATION
|
|
||||||
|
|
||||||
# Checks for libraries
|
|
||||||
PKG_CHECK_MODULES([PROTOCOL], [spice-protocol >= 0.14.2])
|
|
||||||
|
|
||||||
SPICE_CHECK_PYTHON_MODULES()
|
|
||||||
|
|
||||||
SPICE_CHECK_PIXMAN
|
|
||||||
SPICE_CHECK_SMARTCARD
|
|
||||||
SPICE_CHECK_GLIB2
|
|
||||||
SPICE_CHECK_OPUS
|
|
||||||
SPICE_CHECK_OPENSSL
|
|
||||||
SPICE_CHECK_GDK_PIXBUF
|
|
||||||
SPICE_CHECK_UDEV
|
|
||||||
|
|
||||||
SPICE_COMMON_CFLAGS='$(PIXMAN_CFLAGS) $(SMARTCARD_CFLAGS) $(GLIB2_CFLAGS) $(OPUS_CFLAGS) $(OPENSSL_CFLAGS)'
|
|
||||||
SPICE_COMMON_CFLAGS="$SPICE_COMMON_CFLAGS -DG_LOG_DOMAIN=\\\"Spice\\\""
|
|
||||||
SPICE_COMMON_LIBS='$(PIXMAN_LIBS) $(GLIB2_LIBS) $(OPUS_LIBS) $(OPENSSL_LIBS)'
|
|
||||||
AC_SUBST(SPICE_COMMON_CFLAGS)
|
|
||||||
AC_SUBST(SPICE_COMMON_LIBS)
|
|
||||||
|
|
||||||
# The End!
|
|
||||||
AC_CONFIG_FILES([
|
|
||||||
Makefile
|
|
||||||
common/Makefile
|
|
||||||
python_modules/Makefile
|
|
||||||
tests/Makefile
|
|
||||||
docs/Makefile
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_OUTPUT
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
NULL =
|
|
||||||
CLEANFILES =
|
|
||||||
|
|
||||||
ASCIIDOC_FILES = \
|
|
||||||
spice_protocol.txt \
|
|
||||||
spice_uri_scheme.txt \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
ASCIIDOC_FLAGS = -n -a icons -a toc
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
$(ASCIIDOC_FILES) \
|
|
||||||
meson.build \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
if BUILD_HTML_MANUAL
|
|
||||||
ASCIIDOC_HTML = $(ASCIIDOC_FILES:.txt=.html)
|
|
||||||
|
|
||||||
CLEANFILES += $(ASCIIDOC_HTML)
|
|
||||||
|
|
||||||
all-local: $(ASCIIDOC_HTML)
|
|
||||||
|
|
||||||
.txt.html:
|
|
||||||
$(AM_V_GEN)$(ASCIIDOC) $(ASCIIDOC_FLAGS) -o $@ $<
|
|
||||||
endif
|
|
||||||
|
|
||||||
-include $(top_srcdir)/git.mk
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
if get_option('manual')
|
|
||||||
asciidoc = find_program('asciidoc', required : false)
|
|
||||||
if asciidoc.found()
|
|
||||||
foreach f: ['spice_protocol.txt', 'spice_uri_scheme.txt']
|
|
||||||
custom_target('HTML for @0@'.format(f),
|
|
||||||
input : f,
|
|
||||||
output : '@BASENAME@.html',
|
|
||||||
build_by_default : true,
|
|
||||||
command : [asciidoc, '-n', '-a', 'icons', '-a', 'toc', '-o', '@OUTPUT@', '@INPUT@'])
|
|
||||||
endforeach
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
@ -1,477 +0,0 @@
|
|||||||
Spice protocol format file
|
|
||||||
==========================
|
|
||||||
|
|
||||||
Copyright (C) 2016 Red Hat, Inc.
|
|
||||||
Licensed under a Creative Commons Attribution-Share Alike 3.0
|
|
||||||
United States License (see http://creativecommons.org/licenses/by-sa/3.0/us/legalcode).
|
|
||||||
|
|
||||||
Basic
|
|
||||||
-----
|
|
||||||
The spice protocol format file defines the network protocol used by spice.
|
|
||||||
It resemble the C format.
|
|
||||||
|
|
||||||
file ::= <definitions> <protocol> ;
|
|
||||||
definitions ::= <definition>|<definitions><definition> ;
|
|
||||||
definition ::= <typedef>|<structure>|<enum>|<flag>|<message>|<channel> ;
|
|
||||||
protocol ::= "protocol" <identifier> "{" <protocol_channels> "}" ";" ;
|
|
||||||
protocol_channels ::= <protocol_channel>|<protocol_channels><protocol_channel> ;
|
|
||||||
protocol_channel ::= <identifier> <identifier> [ "=" <integer> ] ";" ;
|
|
||||||
integer ::= <hex>|<dec> ;
|
|
||||||
dec ::= [+-][0-9]+ ;
|
|
||||||
hex ::= "0x" [0-9a-f]+ ;
|
|
||||||
identifier ::= [a-z][a-z0-9_]* ;
|
|
||||||
|
|
||||||
(here BNF with some regular expression is used).
|
|
||||||
|
|
||||||
It's used to generate automatically code to marshal/demarshal the network data.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
channel ExampleChannel {
|
|
||||||
message {
|
|
||||||
uint32 dummy;
|
|
||||||
} Dummy;
|
|
||||||
};
|
|
||||||
|
|
||||||
protocol Example {
|
|
||||||
ExampleChannel first = 1001;
|
|
||||||
};
|
|
||||||
|
|
||||||
As you can see brackets like C are used and structures looks like C but you
|
|
||||||
can also see that keywords like `channel`, `protocol`, `message` or some
|
|
||||||
predefined types like `uint32` are proper of the protocol.
|
|
||||||
|
|
||||||
Comments
|
|
||||||
--------
|
|
||||||
Both C and C++ style comments are supported
|
|
||||||
|
|
||||||
// this is a comment
|
|
||||||
/* this is a comment too
|
|
||||||
but can be split in multiple lines */
|
|
||||||
|
|
||||||
Base types
|
|
||||||
----------
|
|
||||||
|
|
||||||
All int from 8 to 64 bit (8, 16, 32 and 64) are supported either signed or unsigned.
|
|
||||||
Also you can pass one unix descriptor.
|
|
||||||
|
|
||||||
base_type ::= "int8"|"uint8"|"int16"|"uint16"|"int32"|"uint32"|"int64"|"uint64"|"unix_fd" ;
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
int16 x;
|
|
||||||
|
|
||||||
Enumerations and flags
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
It's possible to specify enumerations and flags. The difference is that flags are defined as 2 power
|
|
||||||
values and can be combined. Enumerations and flags must have a size (`8`, `16` or `32`) specified.
|
|
||||||
|
|
||||||
enum ::= <enum_type> "{" [ <enumflag_items> ] "}" <attributes> ";" ;
|
|
||||||
flag ::= <flag_type> "{" [ <enumflag_items> ] "}" <attributes> ";" ;
|
|
||||||
enum_type ::= "enum8"|"enum16"|"enum32" ;
|
|
||||||
flag_type ::= "flag8"|"flag16"|"flag32" ;
|
|
||||||
enumflag_items ::= <enumflag_item>|<enumflag_items><enumflag_item>
|
|
||||||
enumflag_item ::= <enum_name> [ "=" <integer> ] [ "," ] ;
|
|
||||||
enum_name ::= [a-z0-9_]* ;
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
enum16 Level {
|
|
||||||
LOW = 0x100,
|
|
||||||
MEDIUM,
|
|
||||||
HIGH = 0x1000
|
|
||||||
};
|
|
||||||
|
|
||||||
Variables
|
|
||||||
---------
|
|
||||||
|
|
||||||
As you should already have noted variables are similar to C syntax but there are
|
|
||||||
some differences.
|
|
||||||
|
|
||||||
variable ::= <type> [ "*" ] <identifier> [ "[" <array_size> "]" ] <attributes>;
|
|
||||||
|
|
||||||
The `*` specify a pointer. This is quite different from C. For the protocol it
|
|
||||||
specifies that in the protocol stream a relative offset is put that points to that
|
|
||||||
variable usually after all defined fields. This happens even on arrays, so for instance
|
|
||||||
|
|
||||||
int32 *n;
|
|
||||||
|
|
||||||
containing a 0x12345678 `n` value could ended up coded as
|
|
||||||
|
|
||||||
04 00 00 00 // 4 as offset
|
|
||||||
78 56 34 12 // `n`
|
|
||||||
|
|
||||||
(little endian). While an array of 2 items defined as
|
|
||||||
|
|
||||||
int32 *n[2];
|
|
||||||
|
|
||||||
and containing 0x12345678 and 0x9abcdef could end up with
|
|
||||||
|
|
||||||
04 00 00 00 // 4 as offset
|
|
||||||
78 56 34 12 // `n`[0]
|
|
||||||
ef cd ab 09 // `n`[1]
|
|
||||||
|
|
||||||
note that `int32 *n[2]` defined a pointer to an array of 2 items and not
|
|
||||||
an array of pointers as C.
|
|
||||||
|
|
||||||
*WARNING*: You should avoid using pointers on protocol if not necessary as they are complicated
|
|
||||||
to handle not using autogenerated code and also use more space on the network.
|
|
||||||
|
|
||||||
Arrays
|
|
||||||
------
|
|
||||||
|
|
||||||
As seen above the easiest way to define an array size is specifying a constant value.
|
|
||||||
However there are multiple way to specify the size
|
|
||||||
|
|
||||||
array_size ::= <integer>|<identifier>|""|<array_size_image>|<array_size_cstring> ;
|
|
||||||
array_size_image ::= "image_size" "(" <integer> "," <identifier> ")" ;
|
|
||||||
array_size_cstring ::= "cstring()" ;
|
|
||||||
|
|
||||||
We already seen integer.
|
|
||||||
Specifying an identifier name instead (should be variable) indicate that the length is specified
|
|
||||||
in another field, for instance
|
|
||||||
|
|
||||||
uint8 name_len;
|
|
||||||
int8 name[name_len];
|
|
||||||
|
|
||||||
allows to put a name of `name_len` len.
|
|
||||||
The empty value tells that the array will end when the containing message end so if we have
|
|
||||||
|
|
||||||
int8 name[];
|
|
||||||
|
|
||||||
and the message is
|
|
||||||
|
|
||||||
66 6f 6f
|
|
||||||
|
|
||||||
possibly the name we want is `foo` (66 6f 6f is the ASCII encoding for `foo`).
|
|
||||||
|
|
||||||
TODO: what happen with two [] in the structure ??
|
|
||||||
TODO: can a [] array not be the last and what happens ??
|
|
||||||
|
|
||||||
`image_size` allow to specify an array holding an image, for instance
|
|
||||||
|
|
||||||
uint16 width;
|
|
||||||
uint16 height;
|
|
||||||
uint8 raw_image[image_size(8, width, height)];
|
|
||||||
|
|
||||||
could contain row data in raw_image. The constant `8` is the bit size of the image.
|
|
||||||
|
|
||||||
`cstring` allows to specify NUL-terminated sequence so having
|
|
||||||
|
|
||||||
int8 name[cstring()];
|
|
||||||
|
|
||||||
and the message as
|
|
||||||
|
|
||||||
66 6f 6f 00
|
|
||||||
|
|
||||||
we'll have the `foo` name. Note that the field does not need to end the message as in `int8 name[]` example.
|
|
||||||
|
|
||||||
Structures
|
|
||||||
----------
|
|
||||||
|
|
||||||
The simplest compound type is the structure. As in C is defined as a list of fields (any variable or switch).
|
|
||||||
But as a protocol definition there are no alignment or padding and every field (beside pointer values) follow each other.
|
|
||||||
|
|
||||||
struct ::= "struct" <identifier> "{" [ <fields> ] "}" <attributes> ";" ;
|
|
||||||
fields ::= <field>|<fields><field> ;
|
|
||||||
field ::= <variable>|<switch>
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
struct Point {
|
|
||||||
int32 x;
|
|
||||||
int32 y;
|
|
||||||
};
|
|
||||||
|
|
||||||
Messages
|
|
||||||
--------
|
|
||||||
|
|
||||||
Messages have the same syntax of structure (beside `message`) with the difference that they can
|
|
||||||
be used directly inside channels.
|
|
||||||
|
|
||||||
message ::= "message" <identifier> "{" [ <fields> ] "}" <attributes> ";" ;
|
|
||||||
|
|
||||||
Switches
|
|
||||||
--------
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
Type definitions
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Like C type definition allow to short types defining new ones.
|
|
||||||
|
|
||||||
typedef ::= "typedef" <identifier> <type> <attributes> ;
|
|
||||||
|
|
||||||
note that unlike C name came before the type.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
typedef XCoord int32;
|
|
||||||
|
|
||||||
Channels
|
|
||||||
--------
|
|
||||||
|
|
||||||
channel ::= "channel" <identifier> [ ":" <identifier> ] "{" <channel_messages> "}" <attributes> ";" ;
|
|
||||||
channel_messages ::= <channel_message>|<channel_messages><channel_message> ;
|
|
||||||
channel_message ::= "server:" | "client:" | "message" <identifier> [ "=" <integer> ] ;
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
channel ExampleChannel {
|
|
||||||
server:
|
|
||||||
message {
|
|
||||||
uint32 dummy;
|
|
||||||
} Dummy;
|
|
||||||
};
|
|
||||||
|
|
||||||
Note that every message is associated with a number which is used in the protocol.
|
|
||||||
The assignment work in a similar way to enumeration in C beside first message is
|
|
||||||
assigned 1 value and not 0. So first message (if no integer is specified) is assigned
|
|
||||||
1, second 2 and so on.
|
|
||||||
|
|
||||||
`server:` or `client:` specify the direction of messages following, `server` specify
|
|
||||||
messages from server while `client` from client. If not specified is assumed from
|
|
||||||
server.
|
|
||||||
|
|
||||||
For each channel you can specify a parent channel. Derived channel inherits all
|
|
||||||
messages specified in the parent.
|
|
||||||
Note that messages from parent can be overridden by derived channels.
|
|
||||||
|
|
||||||
Protocol
|
|
||||||
--------
|
|
||||||
|
|
||||||
protocol ::= "protocol" <identifier> "{" <protocol_channels> "}" ";" ;
|
|
||||||
protocol_channels ::= <protocol_channel>|<protocol_channels><protocol_channel> ;
|
|
||||||
protocol_channel ::= <identifier> <identifier> [ "=" <integer> ] ";" ;
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
protocol Example {
|
|
||||||
ExampleChannel first = 1001;
|
|
||||||
};
|
|
||||||
|
|
||||||
Protocol specify the list of channel supported. Channel have an associated number
|
|
||||||
assigned in a similar way of channels (incremented from one to the next with
|
|
||||||
first starting from 0 if not specified).
|
|
||||||
|
|
||||||
*NOTE*: Due to the way currently code is generate you should use
|
|
||||||
small numbers.
|
|
||||||
|
|
||||||
Attributes
|
|
||||||
----------
|
|
||||||
|
|
||||||
As you probably noted attributed can be specified for lot of definitions.
|
|
||||||
They allow to change code generated or specific constraints of the protocol.
|
|
||||||
|
|
||||||
attributes ::= ""|<attributes><attribute>|<attribute> ;
|
|
||||||
attribute ::= <attribute_name> [ "(" <attribute_values> ")" ] ;
|
|
||||||
attribute_values ::= <attribute_values> "," <attribute_value> | <attribute_value>
|
|
||||||
attribute_value ::= <integer> | <identifier>
|
|
||||||
attribute_name ::= @[a-z][a-z0-9_]* ;
|
|
||||||
|
|
||||||
Mostly of the attributes have no arguments, other currently have only one
|
|
||||||
argument.
|
|
||||||
|
|
||||||
*NOTE*: Some comments are also written in `spice-common` `python_modules/ptypes.py`
|
|
||||||
source file.
|
|
||||||
|
|
||||||
ctype
|
|
||||||
~~~~~
|
|
||||||
|
|
||||||
Specify the structure type name that the generated marshaller/demarshaller code
|
|
||||||
will use. By default the name will be converted to CamelCase and prefixed by
|
|
||||||
`Spice` so for example a structure like
|
|
||||||
|
|
||||||
struct Point {
|
|
||||||
int32 x;
|
|
||||||
int32 y;
|
|
||||||
} @ctype(MyPoint);
|
|
||||||
|
|
||||||
will be marshalled into a C structure like
|
|
||||||
|
|
||||||
struct MyPoint {
|
|
||||||
int32_t x;
|
|
||||||
int32_t y;
|
|
||||||
};
|
|
||||||
|
|
||||||
prefix
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
This attribute allows to specify the prefix used for generated enumerations (both
|
|
||||||
protocol enumerations and flags generate C enumerations). By default the enumeration
|
|
||||||
will use upper case of the enum/flag name prefixed with `SPICE_` and followed by item so
|
|
||||||
|
|
||||||
enum32 level {
|
|
||||||
LOW,
|
|
||||||
HIGH,
|
|
||||||
};
|
|
||||||
|
|
||||||
will generate
|
|
||||||
|
|
||||||
typedef enum SpiceLevel {
|
|
||||||
SPICE_LEVEL_LOW,
|
|
||||||
SPICE_LEVEL_HIGH,
|
|
||||||
SPICE_LEVEL_ENUM_END
|
|
||||||
} SpiceLevel;
|
|
||||||
|
|
||||||
while
|
|
||||||
|
|
||||||
enum32 level {
|
|
||||||
LOW,
|
|
||||||
HIGH,
|
|
||||||
} @prefix(LVL_);
|
|
||||||
|
|
||||||
will generate
|
|
||||||
|
|
||||||
typedef enum SpiceLevel {
|
|
||||||
LVL_LOW,
|
|
||||||
LVL_HIGH,
|
|
||||||
SPICE_LEVEL_ENUM_END
|
|
||||||
} SpiceLevel;
|
|
||||||
|
|
||||||
(note that an automatic `END` enumeration is generated and name is not affected).
|
|
||||||
|
|
||||||
end
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This attribute specifies that the data will be appended/embedded in the final C structure.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
struct test {
|
|
||||||
uint16 len;
|
|
||||||
uint16 array[len] @end;
|
|
||||||
};
|
|
||||||
|
|
||||||
Output C structure:
|
|
||||||
|
|
||||||
struct test {
|
|
||||||
uint16_t len;
|
|
||||||
uint16_t array[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
The generated code will allocate the C structure to allow space for extracted array.
|
|
||||||
|
|
||||||
*WARNING*: This option is usually confused with with empty size protocol. The
|
|
||||||
empty protocol array size specify array that extend on the network data while
|
|
||||||
the `@end` attribute specify to extend the C structure (for instance in the example
|
|
||||||
the attribute was attached to a `len`-sized array).
|
|
||||||
|
|
||||||
to_ptr
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
This specifies that the corresponding C structure field contains a pointer to
|
|
||||||
the data. On marshalling the pointer is used, on demarshalling the data is
|
|
||||||
allocated in the memory block that holds the returned structure.
|
|
||||||
The type of this field must be a structure.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
struct test {
|
|
||||||
uint16 num;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct msg {
|
|
||||||
test ptr @to_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
Output C structure:
|
|
||||||
|
|
||||||
struct test {
|
|
||||||
uint16_t num;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct msg {
|
|
||||||
struct test *ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
nocopy
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
as_ptr
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
nomarshal
|
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
Do not generate code for marshalling this variable.
|
|
||||||
Usually used on last array element to make possible to manually feed data.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
struct Data {
|
|
||||||
uint32 data_size;
|
|
||||||
uint8 data[data_size] @nomarshal;
|
|
||||||
};
|
|
||||||
|
|
||||||
zero_terminated
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The field should terminated by zero.
|
|
||||||
Actually it's not used by python code so it's not enforced and no
|
|
||||||
code is generated.
|
|
||||||
|
|
||||||
marshall
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
nonnull
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
This pointer field cannot be NULL. This means that marshaller assume C structure
|
|
||||||
contain not NULL pointer and demarshaller will fail to demarshall message if offset
|
|
||||||
is 0.
|
|
||||||
|
|
||||||
unique_flag
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
This flag field should contain just a single flag.
|
|
||||||
Actually it's not used by python code so it's not enforced and no
|
|
||||||
code is generated.
|
|
||||||
|
|
||||||
deprecated
|
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
This flag currently apply only to enumerations and flags types and will set
|
|
||||||
generated C enumeration constant to deprecated
|
|
||||||
|
|
||||||
ptr_array
|
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
outvar
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
anon
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
chunk
|
|
||||||
~~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
ifdef
|
|
||||||
~~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
zero
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
virtual
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
TODO
|
|
||||||
@ -1,131 +0,0 @@
|
|||||||
The "spice" URI scheme
|
|
||||||
======================
|
|
||||||
|
|
||||||
This document is inspired by 'The "vnc" URI Scheme' (rfc7869) and
|
|
||||||
attempts to document a standard Spice URI scheme.
|
|
||||||
|
|
||||||
The normative syntax of the Spice URI is defined in the <spice-uri>
|
|
||||||
rule in the following syntax specification. This specification
|
|
||||||
uses the Augmented Backus-Naur Form (ABNF) as described in
|
|
||||||
[RFC5234]. The Spice URI conforms to the generic URI syntax
|
|
||||||
specified in [RFC3986]. The <userinfo>, <host>, <port>,
|
|
||||||
<unreserved>, and <pct-encoded> rules are defined in [RFC3986].
|
|
||||||
|
|
||||||
spice-uri = spice-scheme "://" [ userinfo "@" ] [ host [ ":" port ] ]
|
|
||||||
[ "?" [ spice-params ] ]
|
|
||||||
|
|
||||||
spice-scheme = "spice" / "spice+unix" / "spice+tls"
|
|
||||||
|
|
||||||
spice-params = param "=" value *("&" param "=" value) ["&"]
|
|
||||||
|
|
||||||
param = 1*( param-char )
|
|
||||||
|
|
||||||
value = *( param-char )
|
|
||||||
|
|
||||||
param-char = unreserved / pct-encoded / unreserved-symbols
|
|
||||||
|
|
||||||
unreserved-symbols = ":" / "/" / "@" / "!" / "$" / "'"
|
|
||||||
/ "(" / ")" / "*" / "," / ";"
|
|
||||||
|
|
||||||
The "?", "=", and "&" characters are used to delimit Spice parameters
|
|
||||||
and must be percent-encoded when representing a data octet as
|
|
||||||
specified in [RFC3986]. Within the <spice-params> portion of a Spice
|
|
||||||
URI, the <unreserved-symbols> do not have special meaning and need not
|
|
||||||
be percent-encoded when representing a data octet.
|
|
||||||
|
|
||||||
A Spice URI has the general form:
|
|
||||||
|
|
||||||
spice-scheme://host:port?param1=value1¶m2=value2...
|
|
||||||
|
|
||||||
The host information and each parameter value specify information
|
|
||||||
used in establishing or operating the remote desktop session as
|
|
||||||
specified in Section "URI Parameters".
|
|
||||||
|
|
||||||
URI Parameters
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A description of host information and URI parameters is provided in
|
|
||||||
this section. Information on the constraints of various data types is
|
|
||||||
provided in Section "Data Types". All parameters are considered optional;
|
|
||||||
however, a client will not be able to connect without sufficient
|
|
||||||
information.
|
|
||||||
|
|
||||||
A parameter without a specified default value indicates that no
|
|
||||||
default value is implied by this URI scheme; however, Spice clients
|
|
||||||
can apply implementation-dependent default behaviors otherwise
|
|
||||||
consistent with this document.
|
|
||||||
|
|
||||||
The <host> and <port> values in the "spice://" and "spice+tls://" URIs
|
|
||||||
specify the address of the Spice server on the remote host:
|
|
||||||
|
|
||||||
[options="header"]
|
|
||||||
|=======================================================================
|
|
||||||
| Name | Type | Description | Default
|
|
||||||
| host | string | Spice server hostname or IP | none
|
|
||||||
| port | ushort | Spice server port | none
|
|
||||||
|=======================================================================
|
|
||||||
|
|
||||||
The <host> value in the "spice+unix://" URI specify the UNIX domain
|
|
||||||
socket path of the Spice server on the local host:
|
|
||||||
|
|
||||||
[options="header"]
|
|
||||||
|=======================================================================
|
|
||||||
| Name | Type | Description | Default
|
|
||||||
| host | string | UNIX domain socket path | none
|
|
||||||
|=======================================================================
|
|
||||||
|
|
||||||
The Spice URI parameter values specify remote desktop connection or
|
|
||||||
session properties, including aspects of client operation, usability,
|
|
||||||
and security as specified in the table below:
|
|
||||||
|
|
||||||
[options="header"]
|
|
||||||
|=======================================================================
|
|
||||||
| Name | Type | Description | Default
|
|
||||||
| port | ushort | Spice server port (legacy) | none
|
|
||||||
| tls-port | ushort | Spice server TLS port (legacy) | none
|
|
||||||
| password | string | Spice server password (legacy) | none
|
|
||||||
| ... | | |
|
|
||||||
|=======================================================================
|
|
||||||
|
|
||||||
Parameter names SHOULD be provided in the case specified in this
|
|
||||||
document; however, for compatibility, clients SHOULD accept
|
|
||||||
parameters in a case-insensitive manner. Values SHALL be interpreted
|
|
||||||
in a case-sensitive manner, unless otherwise noted.
|
|
||||||
|
|
||||||
Additional parameters likely to be useful with multiple Spice clients
|
|
||||||
can be added to the "URI Parameters" registry (at the moment,
|
|
||||||
discussed and approved on the Spice mailing list). Individual clients
|
|
||||||
MAY support parameters specific to that client. Spice clients
|
|
||||||
supporting application-specific parameters SHOULD include a
|
|
||||||
distinguishing prefix within the parameter name, such as the name of
|
|
||||||
the application package specified in source code except when precluded
|
|
||||||
by compatibility constraints. For example:
|
|
||||||
|
|
||||||
spice://?com.redhat.spiceclient.MonitorMapping=2&
|
|
||||||
|
|
||||||
It can also be expected that clients will maintain backward
|
|
||||||
compatibility with legacy URI formats and parameters.
|
|
||||||
|
|
||||||
Legacy software applications respond to "spice" URIs in different ways
|
|
||||||
and may fail to behave as expected. It is advisable to test "spice"
|
|
||||||
URIs with specific applications or consult application-specific
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
Data Types
|
|
||||||
----------
|
|
||||||
|
|
||||||
Spice URIs can be percent-encoded as specified in [RFC3986] and MUST
|
|
||||||
be decoded. After decoding, the following type constraints and
|
|
||||||
semantics apply:
|
|
||||||
|
|
||||||
string
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
Values of "string" type are UTF8-encoded strings as specified in
|
|
||||||
[RFC3629].
|
|
||||||
|
|
||||||
ushort
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
The "ushort" values represent unsigned 16-bit integers expressed
|
|
||||||
in decimal digits with value between 0-65535 inclusive.
|
|
||||||
400
git.mk
400
git.mk
@ -1,400 +0,0 @@
|
|||||||
# git.mk, a small Makefile to autogenerate .gitignore files
|
|
||||||
# for autotools-based projects.
|
|
||||||
#
|
|
||||||
# Copyright 2009, Red Hat, Inc.
|
|
||||||
# Copyright 2010,2011,2012,2013 Behdad Esfahbod
|
|
||||||
# Written by Behdad Esfahbod
|
|
||||||
#
|
|
||||||
# Copying and distribution of this file, with or without modification,
|
|
||||||
# is permitted in any medium without royalty provided the copyright
|
|
||||||
# notice and this notice are preserved.
|
|
||||||
#
|
|
||||||
# The latest version of this file can be downloaded from:
|
|
||||||
GIT_MK_URL = https://raw.githubusercontent.com/behdad/git.mk/master/git.mk
|
|
||||||
#
|
|
||||||
# Bugs, etc, should be reported upstream at:
|
|
||||||
# https://github.com/behdad/git.mk
|
|
||||||
#
|
|
||||||
# To use in your project, import this file in your git repo's toplevel,
|
|
||||||
# then do "make -f git.mk". This modifies all Makefile.am files in
|
|
||||||
# your project to -include git.mk. Remember to add that line to new
|
|
||||||
# Makefile.am files you create in your project, or just rerun the
|
|
||||||
# "make -f git.mk".
|
|
||||||
#
|
|
||||||
# This enables automatic .gitignore generation. If you need to ignore
|
|
||||||
# more files, add them to the GITIGNOREFILES variable in your Makefile.am.
|
|
||||||
# But think twice before doing that. If a file has to be in .gitignore,
|
|
||||||
# chances are very high that it's a generated file and should be in one
|
|
||||||
# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES.
|
|
||||||
#
|
|
||||||
# The only case that you need to manually add a file to GITIGNOREFILES is
|
|
||||||
# when remove files in one of mostlyclean-local, clean-local, distclean-local,
|
|
||||||
# or maintainer-clean-local make targets.
|
|
||||||
#
|
|
||||||
# Note that for files like editor backup, etc, there are better places to
|
|
||||||
# ignore them. See "man gitignore".
|
|
||||||
#
|
|
||||||
# If "make maintainer-clean" removes the files but they are not recognized
|
|
||||||
# by this script (that is, if "git status" shows untracked files still), send
|
|
||||||
# me the output of "git status" as well as your Makefile.am and Makefile for
|
|
||||||
# the directories involved and I'll diagnose.
|
|
||||||
#
|
|
||||||
# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see
|
|
||||||
# Makefile.am.sample in the git.mk git repo.
|
|
||||||
#
|
|
||||||
# Don't EXTRA_DIST this file. It is supposed to only live in git clones,
|
|
||||||
# not tarballs. It serves no useful purpose in tarballs and clutters the
|
|
||||||
# build dir.
|
|
||||||
#
|
|
||||||
# This file knows how to handle autoconf, automake, libtool, gtk-doc,
|
|
||||||
# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata,
|
|
||||||
# appstream, hotdoc.
|
|
||||||
#
|
|
||||||
# This makefile provides the following targets:
|
|
||||||
#
|
|
||||||
# - all: "make all" will build all gitignore files.
|
|
||||||
# - gitignore: makes all gitignore files in the current dir and subdirs.
|
|
||||||
# - .gitignore: make gitignore file for the current dir.
|
|
||||||
# - gitignore-recurse: makes all gitignore files in the subdirs.
|
|
||||||
#
|
|
||||||
# KNOWN ISSUES:
|
|
||||||
#
|
|
||||||
# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the
|
|
||||||
# submodule doesn't find us. If you have configure.{in,ac} files in
|
|
||||||
# subdirs, add a proxy git.mk file in those dirs that simply does:
|
|
||||||
# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste.
|
|
||||||
# And add those files to git. See vte/gnome-pty-helper/git.mk for
|
|
||||||
# example.
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Variables user modules may want to add to toplevel MAINTAINERCLEANFILES:
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
#
|
|
||||||
# Most autotools-using modules should be fine including this variable in their
|
|
||||||
# toplevel MAINTAINERCLEANFILES:
|
|
||||||
GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL = \
|
|
||||||
$(srcdir)/aclocal.m4 \
|
|
||||||
$(srcdir)/autoscan.log \
|
|
||||||
$(srcdir)/configure.scan \
|
|
||||||
`AUX_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_AUX_DIR:$$1' ./configure.ac); \
|
|
||||||
test "x$$AUX_DIR" = "x$(srcdir)/" && AUX_DIR=$(srcdir); \
|
|
||||||
for x in \
|
|
||||||
ar-lib \
|
|
||||||
compile \
|
|
||||||
config.guess \
|
|
||||||
config.rpath \
|
|
||||||
config.sub \
|
|
||||||
depcomp \
|
|
||||||
install-sh \
|
|
||||||
ltmain.sh \
|
|
||||||
missing \
|
|
||||||
mkinstalldirs \
|
|
||||||
test-driver \
|
|
||||||
ylwrap \
|
|
||||||
; do echo "$$AUX_DIR/$$x"; done` \
|
|
||||||
`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_HEADERS:$$1' ./configure.ac | \
|
|
||||||
head -n 1 | while read f; do echo "$(srcdir)/$$f.in"; done`
|
|
||||||
#
|
|
||||||
# All modules should also be fine including the following variable, which
|
|
||||||
# removes automake-generated Makefile.in files:
|
|
||||||
GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN = \
|
|
||||||
`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_FILES:$$1' ./configure.ac | \
|
|
||||||
while read f; do \
|
|
||||||
case $$f in Makefile|*/Makefile) \
|
|
||||||
test -f "$(srcdir)/$$f.am" && echo "$(srcdir)/$$f.in";; esac; \
|
|
||||||
done`
|
|
||||||
#
|
|
||||||
# Modules that use libtool and use AC_CONFIG_MACRO_DIR() may also include this,
|
|
||||||
# though it's harmless to include regardless.
|
|
||||||
GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL = \
|
|
||||||
`MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
|
|
||||||
if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \
|
|
||||||
for x in \
|
|
||||||
libtool.m4 \
|
|
||||||
ltoptions.m4 \
|
|
||||||
ltsugar.m4 \
|
|
||||||
ltversion.m4 \
|
|
||||||
lt~obsolete.m4 \
|
|
||||||
; do echo "$$MACRO_DIR/$$x"; done; \
|
|
||||||
fi`
|
|
||||||
#
|
|
||||||
# Modules that use gettext and use AC_CONFIG_MACRO_DIR() may also include this,
|
|
||||||
# though it's harmless to include regardless.
|
|
||||||
GITIGNORE_MAINTAINERCLEANFILES_M4_GETTEXT = \
|
|
||||||
`MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
|
|
||||||
if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \
|
|
||||||
for x in \
|
|
||||||
codeset.m4 \
|
|
||||||
extern-inline.m4 \
|
|
||||||
fcntl-o.m4 \
|
|
||||||
gettext.m4 \
|
|
||||||
glibc2.m4 \
|
|
||||||
glibc21.m4 \
|
|
||||||
iconv.m4 \
|
|
||||||
intdiv0.m4 \
|
|
||||||
intl.m4 \
|
|
||||||
intldir.m4 \
|
|
||||||
intlmacosx.m4 \
|
|
||||||
intmax.m4 \
|
|
||||||
inttypes-pri.m4 \
|
|
||||||
inttypes_h.m4 \
|
|
||||||
lcmessage.m4 \
|
|
||||||
lib-ld.m4 \
|
|
||||||
lib-link.m4 \
|
|
||||||
lib-prefix.m4 \
|
|
||||||
lock.m4 \
|
|
||||||
longlong.m4 \
|
|
||||||
nls.m4 \
|
|
||||||
po.m4 \
|
|
||||||
printf-posix.m4 \
|
|
||||||
progtest.m4 \
|
|
||||||
size_max.m4 \
|
|
||||||
stdint_h.m4 \
|
|
||||||
threadlib.m4 \
|
|
||||||
uintmax_t.m4 \
|
|
||||||
visibility.m4 \
|
|
||||||
wchar_t.m4 \
|
|
||||||
wint_t.m4 \
|
|
||||||
xsize.m4 \
|
|
||||||
; do echo "$$MACRO_DIR/$$x"; done; \
|
|
||||||
fi`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Default rule is to install ourselves in all Makefile.am files:
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
git-all: git-mk-install
|
|
||||||
|
|
||||||
git-mk-install:
|
|
||||||
@echo "Installing git makefile"
|
|
||||||
@any_failed=; \
|
|
||||||
find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while read x; do \
|
|
||||||
if grep 'include .*/git.mk' $$x >/dev/null; then \
|
|
||||||
echo "$$x already includes git.mk"; \
|
|
||||||
else \
|
|
||||||
failed=; \
|
|
||||||
echo "Updating $$x"; \
|
|
||||||
{ cat $$x; \
|
|
||||||
echo ''; \
|
|
||||||
echo '-include $$(top_srcdir)/git.mk'; \
|
|
||||||
} > $$x.tmp || failed=1; \
|
|
||||||
if test x$$failed = x; then \
|
|
||||||
mv $$x.tmp $$x || failed=1; \
|
|
||||||
fi; \
|
|
||||||
if test x$$failed = x; then : else \
|
|
||||||
echo "Failed updating $$x"; >&2 \
|
|
||||||
any_failed=1; \
|
|
||||||
fi; \
|
|
||||||
fi; done; test -z "$$any_failed"
|
|
||||||
|
|
||||||
git-mk-update:
|
|
||||||
wget $(GIT_MK_URL) -O $(top_srcdir)/git.mk
|
|
||||||
|
|
||||||
.PHONY: git-all git-mk-install git-mk-update
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Actual .gitignore generation:
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(top_srcdir)/configure.ac
|
|
||||||
@echo "git.mk: Generating $@"
|
|
||||||
@{ \
|
|
||||||
if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
|
|
||||||
for x in \
|
|
||||||
$(DOC_MODULE)-decl-list.txt \
|
|
||||||
$(DOC_MODULE)-decl.txt \
|
|
||||||
tmpl/$(DOC_MODULE)-unused.sgml \
|
|
||||||
"tmpl/*.bak" \
|
|
||||||
$(REPORT_FILES) \
|
|
||||||
$(DOC_MODULE).pdf \
|
|
||||||
xml html \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
FLAVOR=$$(cd $(top_srcdir); $(AUTOCONF) --trace 'GTK_DOC_CHECK:$$2' ./configure.ac); \
|
|
||||||
case $$FLAVOR in *no-tmpl*) echo /tmpl;; esac; \
|
|
||||||
if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-types"; then \
|
|
||||||
echo "/$(DOC_MODULE).types"; \
|
|
||||||
fi; \
|
|
||||||
if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-sections"; then \
|
|
||||||
echo "/$(DOC_MODULE)-sections.txt"; \
|
|
||||||
fi; \
|
|
||||||
if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
|
|
||||||
for x in \
|
|
||||||
$(SETUP_FILES) \
|
|
||||||
$(DOC_MODULE).types \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
fi; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
|
|
||||||
for lc in $(DOC_LINGUAS); do \
|
|
||||||
for x in \
|
|
||||||
$(if $(DOC_MODULE),$(DOC_MODULE).xml) \
|
|
||||||
$(DOC_PAGES) \
|
|
||||||
$(DOC_INCLUDES) \
|
|
||||||
; do echo "/$$lc/$$x"; done; \
|
|
||||||
done; \
|
|
||||||
for x in \
|
|
||||||
$(_DOC_OMF_ALL) \
|
|
||||||
$(_DOC_DSK_ALL) \
|
|
||||||
$(_DOC_HTML_ALL) \
|
|
||||||
$(_DOC_MOFILES) \
|
|
||||||
$(DOC_H_FILE) \
|
|
||||||
"*/.xml2po.mo" \
|
|
||||||
"*/*.omf.out" \
|
|
||||||
; do echo /$$x; done; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(HOTDOC)" = x; then :; else \
|
|
||||||
$(foreach project, $(HOTDOC_PROJECTS),echo "/$(call HOTDOC_TARGET,$(project))"; \
|
|
||||||
echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-conf-path output)" ; \
|
|
||||||
echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-private-folder)" ; \
|
|
||||||
) \
|
|
||||||
for x in \
|
|
||||||
.hotdoc.d \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \
|
|
||||||
for lc in $(HELP_LINGUAS); do \
|
|
||||||
for x in \
|
|
||||||
$(HELP_FILES) \
|
|
||||||
"$$lc.stamp" \
|
|
||||||
"$$lc.mo" \
|
|
||||||
; do echo "/$$lc/$$x"; done; \
|
|
||||||
done; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(gsettings_SCHEMAS)" = x; then :; else \
|
|
||||||
for x in \
|
|
||||||
$(gsettings_SCHEMAS:.xml=.valid) \
|
|
||||||
$(gsettings__enum_file) \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(appdata_XML)" = x; then :; else \
|
|
||||||
for x in \
|
|
||||||
$(appdata_XML:.xml=.valid) \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(appstream_XML)" = x; then :; else \
|
|
||||||
for x in \
|
|
||||||
$(appstream_XML:.xml=.valid) \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
fi; \
|
|
||||||
if test -f $(srcdir)/po/Makefile.in.in; then \
|
|
||||||
for x in \
|
|
||||||
ABOUT-NLS \
|
|
||||||
po/Makefile.in.in \
|
|
||||||
po/Makefile.in.in~ \
|
|
||||||
po/Makefile.in \
|
|
||||||
po/Makefile \
|
|
||||||
po/Makevars.template \
|
|
||||||
po/POTFILES \
|
|
||||||
po/Rules-quot \
|
|
||||||
po/stamp-it \
|
|
||||||
po/stamp-po \
|
|
||||||
po/.intltool-merge-cache \
|
|
||||||
"po/*.gmo" \
|
|
||||||
"po/*.header" \
|
|
||||||
"po/*.mo" \
|
|
||||||
"po/*.sed" \
|
|
||||||
"po/*.sin" \
|
|
||||||
po/$(GETTEXT_PACKAGE).pot \
|
|
||||||
intltool-extract.in \
|
|
||||||
intltool-merge.in \
|
|
||||||
intltool-update.in \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
fi; \
|
|
||||||
if test -f $(srcdir)/configure; then \
|
|
||||||
for x in \
|
|
||||||
autom4te.cache \
|
|
||||||
configure \
|
|
||||||
config.h \
|
|
||||||
stamp-h1 \
|
|
||||||
libtool \
|
|
||||||
config.lt \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(DEJATOOL)" = x; then :; else \
|
|
||||||
for x in \
|
|
||||||
$(DEJATOOL) \
|
|
||||||
; do echo "/$$x.sum"; echo "/$$x.log"; done; \
|
|
||||||
echo /site.exp; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(am__dirstamp)" = x; then :; else \
|
|
||||||
echo "$(am__dirstamp)"; \
|
|
||||||
fi; \
|
|
||||||
if test "x$(findstring libtool,$(LTCOMPILE))" = x -a "x$(findstring libtool,$(LTCXXCOMPILE))" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
|
|
||||||
for x in \
|
|
||||||
"*.lo" \
|
|
||||||
".libs" "_libs" \
|
|
||||||
; do echo "$$x"; done; \
|
|
||||||
fi; \
|
|
||||||
for x in \
|
|
||||||
.gitignore \
|
|
||||||
$(GITIGNOREFILES) \
|
|
||||||
$(CLEANFILES) \
|
|
||||||
$(PROGRAMS) $(check_PROGRAMS) $(EXTRA_PROGRAMS) \
|
|
||||||
$(LIBRARIES) $(check_LIBRARIES) $(EXTRA_LIBRARIES) \
|
|
||||||
$(LTLIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \
|
|
||||||
so_locations \
|
|
||||||
$(MOSTLYCLEANFILES) \
|
|
||||||
$(TEST_LOGS) \
|
|
||||||
$(TEST_LOGS:.log=.trs) \
|
|
||||||
$(TEST_SUITE_LOG) \
|
|
||||||
$(TESTS:=.test) \
|
|
||||||
"*.gcda" \
|
|
||||||
"*.gcno" \
|
|
||||||
$(DISTCLEANFILES) \
|
|
||||||
$(am__CONFIG_DISTCLEAN_FILES) \
|
|
||||||
$(CONFIG_CLEAN_FILES) \
|
|
||||||
TAGS ID GTAGS GRTAGS GSYMS GPATH tags \
|
|
||||||
"*.tab.c" \
|
|
||||||
$(MAINTAINERCLEANFILES) \
|
|
||||||
$(BUILT_SOURCES) \
|
|
||||||
$(patsubst %.vala,%.c,$(filter %.vala,$(SOURCES))) \
|
|
||||||
$(filter %_vala.stamp,$(DIST_COMMON)) \
|
|
||||||
$(filter %.vapi,$(DIST_COMMON)) \
|
|
||||||
$(filter $(addprefix %,$(notdir $(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))))),$(DIST_COMMON)) \
|
|
||||||
Makefile \
|
|
||||||
Makefile.in \
|
|
||||||
"*.orig" \
|
|
||||||
"*.rej" \
|
|
||||||
"*.bak" \
|
|
||||||
"*~" \
|
|
||||||
".*.sw[nop]" \
|
|
||||||
".dirstamp" \
|
|
||||||
; do echo "/$$x"; done; \
|
|
||||||
for x in \
|
|
||||||
"*.$(OBJEXT)" \
|
|
||||||
$(DEPDIR) \
|
|
||||||
; do echo "$$x"; done; \
|
|
||||||
} | \
|
|
||||||
sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
|
|
||||||
sed 's@/[.]/@/@g' | \
|
|
||||||
LC_ALL=C sort | uniq > $@.tmp && \
|
|
||||||
mv $@.tmp $@;
|
|
||||||
|
|
||||||
all: $(srcdir)/.gitignore gitignore-recurse-maybe
|
|
||||||
gitignore: $(srcdir)/.gitignore gitignore-recurse
|
|
||||||
|
|
||||||
gitignore-recurse-maybe:
|
|
||||||
@for subdir in $(DIST_SUBDIRS); do \
|
|
||||||
case " $(SUBDIRS) " in \
|
|
||||||
*" $$subdir "*) :;; \
|
|
||||||
*) test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir");; \
|
|
||||||
esac; \
|
|
||||||
done
|
|
||||||
gitignore-recurse:
|
|
||||||
@for subdir in $(DIST_SUBDIRS); do \
|
|
||||||
test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir"); \
|
|
||||||
done
|
|
||||||
|
|
||||||
maintainer-clean: gitignore-clean
|
|
||||||
gitignore-clean:
|
|
||||||
-rm -f $(srcdir)/.gitignore
|
|
||||||
|
|
||||||
.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe
|
|
||||||
0
m4/.gitignore
vendored
0
m4/.gitignore
vendored
@ -1,49 +0,0 @@
|
|||||||
# ===========================================================================
|
|
||||||
# http://www.gnu.org/software/autoconf-archive/ax_python_module.html
|
|
||||||
# ===========================================================================
|
|
||||||
#
|
|
||||||
# SYNOPSIS
|
|
||||||
#
|
|
||||||
# AX_PYTHON_MODULE(modname[, fatal])
|
|
||||||
#
|
|
||||||
# DESCRIPTION
|
|
||||||
#
|
|
||||||
# Checks for Python module.
|
|
||||||
#
|
|
||||||
# If fatal is non-empty then absence of a module will trigger an error.
|
|
||||||
#
|
|
||||||
# LICENSE
|
|
||||||
#
|
|
||||||
# Copyright (c) 2008 Andrew Collier
|
|
||||||
#
|
|
||||||
# Copying and distribution of this file, with or without modification, are
|
|
||||||
# permitted in any medium without royalty provided the copyright notice
|
|
||||||
# and this notice are preserved. This file is offered as-is, without any
|
|
||||||
# warranty.
|
|
||||||
|
|
||||||
#serial 6
|
|
||||||
|
|
||||||
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
|
|
||||||
AC_DEFUN([AX_PYTHON_MODULE],[
|
|
||||||
if test -z $PYTHON;
|
|
||||||
then
|
|
||||||
PYTHON="python"
|
|
||||||
fi
|
|
||||||
PYTHON_NAME=`basename $PYTHON`
|
|
||||||
AC_MSG_CHECKING($PYTHON_NAME module: $1)
|
|
||||||
$PYTHON -c "import $1" 2>/dev/null
|
|
||||||
if test $? -eq 0;
|
|
||||||
then
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
|
|
||||||
else
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
eval AS_TR_CPP(HAVE_PYMOD_$1)=no
|
|
||||||
#
|
|
||||||
if test -n "$2"
|
|
||||||
then
|
|
||||||
AC_MSG_ERROR(failed to find required module $1)
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
dnl This file should be included by spice-common user from
|
|
||||||
dnl configure.ac to have all required checks in order to use spice-common
|
|
||||||
m4_define(spice_common_dir,m4_bpatsubst(__file__,[/m4/common\.m4],[]))dnl
|
|
||||||
dnl Automatically include m4 files in m4 directory
|
|
||||||
AC_CONFIG_MACRO_DIRS(spice_common_dir[/m4])dnl
|
|
||||||
SPICE_COMMON(spice_common_dir)
|
|
||||||
368
m4/spice-deps.m4
368
m4/spice-deps.m4
@ -1,368 +0,0 @@
|
|||||||
# SPICE_WARNING(warning)
|
|
||||||
# SPICE_PRINT_MESSAGES
|
|
||||||
# ----------------------
|
|
||||||
# Collect warnings and print them at the end so they are clearly visible.
|
|
||||||
# ---------------------
|
|
||||||
AC_DEFUN([SPICE_WARNING],[AS_VAR_APPEND([spice_warnings],["|$1"])])
|
|
||||||
AC_DEFUN([SPICE_PRINT_MESSAGES],[
|
|
||||||
ac_save_IFS="$IFS"
|
|
||||||
IFS="|"
|
|
||||||
for msg in $spice_warnings; do
|
|
||||||
IFS="$ac_save_IFS"
|
|
||||||
AS_VAR_IF([msg],[],,[AC_MSG_WARN([$msg]); echo >&2])
|
|
||||||
done
|
|
||||||
IFS="$ac_save_IFS"
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# SPICE_EXTRA_CHECKS()
|
|
||||||
# --------------------
|
|
||||||
# Check for --enable-extra-checks option
|
|
||||||
# --------------------
|
|
||||||
AC_DEFUN([SPICE_EXTRA_CHECKS],[
|
|
||||||
AC_ARG_ENABLE([extra-checks],
|
|
||||||
AS_HELP_STRING([--enable-extra-checks=@<:@yes/no@:>@],
|
|
||||||
[Enable expensive checks @<:@default=no@:>@]))
|
|
||||||
AM_CONDITIONAL(ENABLE_EXTRA_CHECKS, test "x$enable_extra_checks" = "xyes")
|
|
||||||
AM_COND_IF([ENABLE_EXTRA_CHECKS], AC_DEFINE([ENABLE_EXTRA_CHECKS], 1, [Enable extra checks on code]))
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# SPICE_CHECK_SYSDEPS()
|
|
||||||
# ---------------------
|
|
||||||
# Checks for header files and library functions needed by spice-common.
|
|
||||||
# ---------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_SYSDEPS], [
|
|
||||||
AC_C_BIGENDIAN
|
|
||||||
AC_FUNC_ALLOCA
|
|
||||||
AC_CHECK_HEADERS([arpa/inet.h netinet/in.h stdlib.h sys/socket.h unistd.h])
|
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics
|
|
||||||
AC_C_INLINE
|
|
||||||
|
|
||||||
# Checks for library functions
|
|
||||||
# do not check malloc or realloc, since that cannot be cross-compiled checked
|
|
||||||
AC_CHECK_FUNCS([floor])
|
|
||||||
AC_SEARCH_LIBS([hypot], [m], [], [
|
|
||||||
AC_MSG_ERROR([unable to find the hypot() function])
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# SPICE_CHECK_SMARTCARD
|
|
||||||
# ---------------------
|
|
||||||
# Adds a --enable-smartcard switch in order to enable/disable smartcard
|
|
||||||
# support, and checks if the needed libraries are available. If found, it will
|
|
||||||
# return the flags to use in the SMARTCARD_CFLAGS and SMARTCARD_LIBS variables, and
|
|
||||||
# it will define a USE_SMARTCARD preprocessor symbol as well as a HAVE_SMARTCARD
|
|
||||||
# Makefile conditional.
|
|
||||||
#----------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_SMARTCARD], [
|
|
||||||
AC_ARG_ENABLE([smartcard],
|
|
||||||
AS_HELP_STRING([--enable-smartcard=@<:@yes/no/auto@:>@],
|
|
||||||
[Enable smartcard support @<:@default=auto@:>@]),
|
|
||||||
[],
|
|
||||||
[enable_smartcard="auto"])
|
|
||||||
|
|
||||||
have_smartcard=no
|
|
||||||
if test "x$enable_smartcard" != "xno"; then
|
|
||||||
PKG_CHECK_MODULES([SMARTCARD], [libcacard >= 2.5.1], [have_smartcard=yes], [have_smartcard=no])
|
|
||||||
if test "x$enable_smartcard" = "xyes" && test "x$have_smartcard" = "xno"; then
|
|
||||||
AC_MSG_ERROR([smarcard support explicitly requested, but some required packages are not available])
|
|
||||||
fi
|
|
||||||
if test "x$have_smartcard" = "xyes"; then
|
|
||||||
AC_DEFINE(USE_SMARTCARD, [1], [Define if supporting smartcard proxying])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(HAVE_SMARTCARD, test "x$have_smartcard" = "xyes")
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# SPICE_CHECK_OPUS
|
|
||||||
# ----------------
|
|
||||||
# Check for the availability of Opus. If found, it will return the flags to use
|
|
||||||
# in the OPUS_CFLAGS and OPUS_LIBS variables, and it will define a
|
|
||||||
# HAVE_OPUS preprocessor symbol as well as a HAVE_OPUS Makefile conditional.
|
|
||||||
# ----------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_OPUS], [
|
|
||||||
AC_ARG_ENABLE([opus],
|
|
||||||
[ --disable-opus Disable Opus audio codec (enabled by default)],,
|
|
||||||
[enable_opus="auto"])
|
|
||||||
if test "x$enable_opus" != "xno"; then
|
|
||||||
PKG_CHECK_MODULES([OPUS], [opus >= 0.9.14], [have_opus=yes], [have_opus=no])
|
|
||||||
if test "x$enable_opus" = "xauto" && test "x$have_opus" = "xno"; then
|
|
||||||
AC_MSG_ERROR([Opus could not be detected, explicitly use --disable-opus if that's intentional])
|
|
||||||
fi
|
|
||||||
if test "x$enable_opus" = "xyes" && test "x$have_opus" != "xyes"; then
|
|
||||||
AC_MSG_ERROR([--enable-opus has been specified, but Opus is missing])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
AM_CONDITIONAL([HAVE_OPUS], [test "x$have_opus" = "xyes"])
|
|
||||||
AM_COND_IF([HAVE_OPUS], AC_DEFINE([HAVE_OPUS], [1], [Define if we have OPUS]))
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# SPICE_CHECK_PIXMAN
|
|
||||||
# ------------------
|
|
||||||
# Check for the availability of pixman. If found, it will return the flags to
|
|
||||||
# use in the PIXMAN_CFLAGS and PIXMAN_LIBS variables.
|
|
||||||
#-------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_PIXMAN], [
|
|
||||||
PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.17.7)
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# SPICE_CHECK_GLIB2
|
|
||||||
# -----------------
|
|
||||||
# Check for the availability of glib2. If found, it will return the flags to
|
|
||||||
# use in the GLIB2_CFLAGS and GLIB2_LIBS variables.
|
|
||||||
#------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_GLIB2], [
|
|
||||||
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.38)
|
|
||||||
PKG_CHECK_MODULES(GIO2, gio-2.0 >= 2.38)
|
|
||||||
GLIB2_CFLAGS="$GLIB2_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_38 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_38"
|
|
||||||
])
|
|
||||||
|
|
||||||
# SPICE_CHECK_GDK_PIXBUF
|
|
||||||
# ----------------------
|
|
||||||
# Check for the availability of gdk-pixbuf. If found, it will return the flags to use
|
|
||||||
# in the GDK_PIXBUF_CFLAGS and GDK_PIXBUF_LIBS variables, and it will define a
|
|
||||||
# HAVE_GDK_PIXBUF preprocessor symbol as well as a HAVE_GDK_PIXBUF Makefile conditional.
|
|
||||||
# ----------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_GDK_PIXBUF], [
|
|
||||||
PKG_CHECK_MODULES([GDK_PIXBUF], [gdk-pixbuf-2.0 >= 2.26], [have_gdk_pixbuf=yes], [have_gdk_pixbuf=no])
|
|
||||||
|
|
||||||
AM_CONDITIONAL([HAVE_GDK_PIXBUF], [test "x$have_gdk_pixbuf" = "xyes"])
|
|
||||||
AM_COND_IF([HAVE_GDK_PIXBUF], AC_DEFINE([HAVE_GDK_PIXBUF], [1], [Define if gdk-pixbuf was found]))
|
|
||||||
])
|
|
||||||
|
|
||||||
# SPICE_CHECK_PYTHON_MODULES()
|
|
||||||
# --------------------------
|
|
||||||
# Adds a --enable-python-checks configure flags as well as checks for the
|
|
||||||
# availability of the python modules needed by the python scripts generating
|
|
||||||
# C code from spice.proto. These checks are not needed when building from
|
|
||||||
# tarballs so they are disabled by default.
|
|
||||||
#---------------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_PYTHON_MODULES], [
|
|
||||||
AC_ARG_ENABLE([python-checks],
|
|
||||||
AS_HELP_STRING([--enable-python-checks=@<:@yes/no@:>@],
|
|
||||||
[Enable checks for Python modules needed to build from git @<:@default=no@:>@]),
|
|
||||||
[],
|
|
||||||
[enable_python_checks="no"])
|
|
||||||
if test "x$enable_python_checks" != "xno"; then
|
|
||||||
AS_IF([test -n "$PYTHON"], # already set required PYTHON version
|
|
||||||
[AM_PATH_PYTHON
|
|
||||||
AX_PYTHON_MODULE([pyparsing], [1])],
|
|
||||||
[PYTHON=python3
|
|
||||||
AX_PYTHON_MODULE([pyparsing])
|
|
||||||
test "$HAVE_PYMOD_PYPARSING" = "yes"],
|
|
||||||
[AM_PATH_PYTHON([3])],
|
|
||||||
[AC_MSG_ERROR([Python module pyparsing is required])])
|
|
||||||
else
|
|
||||||
AM_PATH_PYTHON
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# SPICE_CHECK_LZ4
|
|
||||||
# ---------------
|
|
||||||
# Adds a --enable-lz4 switch in order to enable/disable LZ4 compression
|
|
||||||
# support, and checks if the needed libraries are available. If found, it will
|
|
||||||
# return the flags to use in the LZ4_CFLAGS and LZ4_LIBS variables, and
|
|
||||||
# it will define a USE_LZ4 preprocessor symbol and a HAVE_LZ4 conditional.
|
|
||||||
# ---------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_LZ4], [
|
|
||||||
AC_ARG_ENABLE([lz4],
|
|
||||||
AS_HELP_STRING([--enable-lz4=@<:@yes/no/auto@:>@],
|
|
||||||
[Enable LZ4 compression support @<:@default=auto@:>@]),
|
|
||||||
[],
|
|
||||||
[enable_lz4="auto"])
|
|
||||||
|
|
||||||
have_lz4="no"
|
|
||||||
if test "x$enable_lz4" != "xno"; then
|
|
||||||
# LZ4_compress_default is available in liblz4 >= 129, however liblz has changed
|
|
||||||
# versioning scheme making the check failing. Rather check for function definition
|
|
||||||
PKG_CHECK_MODULES([LZ4], [liblz4], [have_lz4="yes"], [have_lz4="no"])
|
|
||||||
|
|
||||||
if test "x$have_lz4" = "xyes"; then
|
|
||||||
# It is necessary to set LIBS and CFLAGS before AC_CHECK_FUNC
|
|
||||||
old_LIBS="$LIBS"
|
|
||||||
old_CFLAGS="$CFLAGS"
|
|
||||||
CFLAGS="$CFLAGS $LZ4_CFLAGS"
|
|
||||||
LIBS="$LIBS $LZ4_LIBS"
|
|
||||||
|
|
||||||
AC_CHECK_FUNC([LZ4_compress_default], [
|
|
||||||
AC_DEFINE(USE_LZ4, [1], [Define to build with lz4 support])],
|
|
||||||
[have_lz4="no"])
|
|
||||||
AC_CHECK_FUNCS([LZ4_compress_fast_continue])
|
|
||||||
|
|
||||||
LIBS="$old_LIBS"
|
|
||||||
CFLAGS="$old_CFLAGS"
|
|
||||||
fi
|
|
||||||
if test "x$enable_lz4" = "xyes" && test "x$have_lz4" = "xno"; then
|
|
||||||
AC_MSG_ERROR([lz4 support requested but liblz4 >= 129 could not be found])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(HAVE_LZ4, test "x$have_lz4" = "xyes")
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# SPICE_CHECK_GSTREAMER(VAR, version, packages-to-check-for, [action-if-found, [action-if-not-found]])
|
|
||||||
# ---------------------
|
|
||||||
# Checks whether the specified GStreamer modules are present and sets the
|
|
||||||
# corresponding autoconf variables and preprocessor definitions.
|
|
||||||
# ---------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_GSTREAMER], [
|
|
||||||
AS_VAR_PUSHDEF([have_gst],[have_]m4_tolower([$1]))dnl
|
|
||||||
AS_VAR_PUSHDEF([gst_inspect],[GST_INSPECT_$2])dnl
|
|
||||||
PKG_CHECK_MODULES([$1], [$3],
|
|
||||||
[have_gst="yes"
|
|
||||||
AC_SUBST(AS_TR_SH([[$1]_CFLAGS]))
|
|
||||||
AC_SUBST(AS_TR_SH([[$1]_LIBS]))
|
|
||||||
AS_VAR_APPEND([SPICE_REQUIRES], [" $3"])
|
|
||||||
AC_DEFINE(AS_TR_SH([HAVE_$1]), [1], [Define if supporting GStreamer $2])
|
|
||||||
AC_PATH_PROG(gst_inspect, gst-inspect-$2)
|
|
||||||
AS_IF([test "x$gst_inspect" = x],
|
|
||||||
SPICE_WARNING([Cannot verify that the required runtime GStreamer $2 elements are present because gst-inspect-$2 is missing]))
|
|
||||||
$4],
|
|
||||||
[have_gst="no"
|
|
||||||
$5])
|
|
||||||
AS_VAR_POPDEF([gst_inspect])dnl
|
|
||||||
AS_VAR_POPDEF([have_gst])dnl
|
|
||||||
])
|
|
||||||
|
|
||||||
# SPICE_CHECK_GSTREAMER_ELEMENTS(gst-inspect, package, elements-to-check-for)
|
|
||||||
# ---------------------
|
|
||||||
# Checks that the specified GStreamer elements are installed. If not it
|
|
||||||
# issues a warning and sets missing_gstreamer_elements.
|
|
||||||
# ---------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_GSTREAMER_ELEMENTS], [
|
|
||||||
AS_IF([test "x$1" != x],
|
|
||||||
[missing=""
|
|
||||||
for element in $3
|
|
||||||
do
|
|
||||||
AS_VAR_PUSHDEF([cache_var],[spice_cv_prog_${1}_${element}])dnl
|
|
||||||
AC_CACHE_CHECK([for the $element GStreamer element], cache_var,
|
|
||||||
[found=no
|
|
||||||
"$1" $element >/dev/null 2>/dev/null && found=yes
|
|
||||||
eval "cache_var=$found"])
|
|
||||||
AS_VAR_COPY(res, cache_var)
|
|
||||||
AS_IF([test "x$res" = "xno"], [missing="$missing $element"])
|
|
||||||
AS_VAR_POPDEF([cache_var])dnl
|
|
||||||
done
|
|
||||||
AS_IF([test "x$missing" != x],
|
|
||||||
[SPICE_WARNING([The$missing GStreamer element(s) are missing. You should be able to find them in the $2 package.])
|
|
||||||
missing_gstreamer_elements="yes"],
|
|
||||||
[test "x$missing_gstreamer_elements" = x],
|
|
||||||
[missing_gstreamer_elements="no"])
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
# SPICE_CHECK_SASL
|
|
||||||
# ----------------
|
|
||||||
# Adds a --with-sasl switch to allow using SASL for authentication.
|
|
||||||
# Checks whether the required library is available. If it is present,
|
|
||||||
# it will return the flags to use in SASL_CFLAGS and SASL_LIBS variables,
|
|
||||||
# and it will define a have_sasl configure variable and a HAVE_SASL preprocessor
|
|
||||||
# symbol.
|
|
||||||
# ----------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_SASL], [
|
|
||||||
AC_ARG_WITH([sasl],
|
|
||||||
[AS_HELP_STRING([--with-sasl=@<:@yes/no/auto@:>@],
|
|
||||||
[use cyrus SASL for authentication @<:@default=auto@:>@])],
|
|
||||||
[],
|
|
||||||
[with_sasl="auto"])
|
|
||||||
|
|
||||||
have_sasl=no
|
|
||||||
if test "x$with_sasl" != "xno"; then
|
|
||||||
PKG_CHECK_MODULES([SASL], [libsasl2], [have_sasl=yes],[have_sasl=no])
|
|
||||||
if test "x$have_sasl" = "xno" && test "x$with_sasl" = "xyes"; then
|
|
||||||
AC_MSG_ERROR([Cyrus SASL support requested but libsasl2 could not be found])
|
|
||||||
fi
|
|
||||||
if test "x$have_sasl" = "xyes"; then
|
|
||||||
AC_DEFINE([HAVE_SASL], 1, [whether Cyrus SASL is available for authentication])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
|
|
||||||
# SPICE_CHECK_OPENSSL
|
|
||||||
# -----------------
|
|
||||||
# Check for the availability of openssl. If found, it will return the flags to
|
|
||||||
# use in the OPENSSL_CFLAGS and OPENSSL_LIBS variables.
|
|
||||||
#------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_OPENSSL], [
|
|
||||||
PKG_CHECK_MODULES(OPENSSL, openssl)
|
|
||||||
])
|
|
||||||
|
|
||||||
# SPICE_CHECK_UDEV
|
|
||||||
# -----------------
|
|
||||||
# Check for the availability of libudev. If found, it will help to determine
|
|
||||||
# if a given vendor GPU is available or not.
|
|
||||||
#------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_UDEV], [
|
|
||||||
PKG_CHECK_MODULES([UDEV], [libudev], [have_udev=yes],[have_udev=no])
|
|
||||||
if test "x$have_udev" = "xyes"; then
|
|
||||||
AC_DEFINE([HAVE_UDEV], 1, [whether libudev is available to identify GPU])
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
|
|
||||||
# SPICE_CHECK_INSTRUMENTATION
|
|
||||||
# -----------------
|
|
||||||
# Check for the availability of an instrumentation library.
|
|
||||||
#------------------
|
|
||||||
AC_DEFUN([SPICE_CHECK_INSTRUMENTATION], [
|
|
||||||
AC_ARG_ENABLE([instrumentation],
|
|
||||||
AS_HELP_STRING([--enable-instrumentation=@<:@recorder/agent/no@:>@],
|
|
||||||
[Enable instrumentation @<:@default=no@:>@]),
|
|
||||||
[],
|
|
||||||
enable_instrumentation="no")
|
|
||||||
AS_IF([test "$enable_instrumentation" = "recorder"],
|
|
||||||
AC_DEFINE([ENABLE_RECORDER], [1], [Define if the recorder instrumentation is enabled]))
|
|
||||||
AS_IF([test "$enable_instrumentation" = "agent"],
|
|
||||||
AC_DEFINE([ENABLE_AGENT_INTERFACE], [1], [Define if the agent-interface instrumentation is enabled]))
|
|
||||||
AM_CONDITIONAL([ENABLE_RECORDER],[test "$enable_instrumentation" = "recorder"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AGENT_INTERFACE],[test "$enable_instrumentation" = "agent"])
|
|
||||||
])
|
|
||||||
|
|
||||||
# SPICE_COMMON
|
|
||||||
# -----------------
|
|
||||||
# Define variables in order to use spice-common
|
|
||||||
# SPICE_COMMON_DIR directory for output libraries
|
|
||||||
# SPICE_COMMON_CFLAGS CFLAGS to add to use the library
|
|
||||||
#
|
|
||||||
# SPICE_PROTOCOL_MIN_VER input (m4) and output (autoconf) SPICE protocol version
|
|
||||||
# SPICE_PROTOCOL_CFLAGS CFLAGS for SPICE protocol, already automatically included
|
|
||||||
#
|
|
||||||
# GLIB2_MIN_VER input (m4) and output (shell) GLib2 minimum version
|
|
||||||
# GLIB2_MIN_VERSION output (shell) variable like "GLIB_VERSION_1_2" from GLIB2_MIN_VER
|
|
||||||
#------------------
|
|
||||||
AC_DEFUN([SPICE_COMMON], [dnl
|
|
||||||
dnl These add some flags and checks to component using spice-common
|
|
||||||
dnl The flags are necessary in order to make included header working
|
|
||||||
AC_REQUIRE([SPICE_EXTRA_CHECKS])dnl
|
|
||||||
AC_REQUIRE([SPICE_CHECK_INSTRUMENTATION])dnl
|
|
||||||
dnl Get the required spice protocol version
|
|
||||||
m4_define([SPICE_PROTOCOL_MIN_VER],m4_ifdef([SPICE_PROTOCOL_MIN_VER],SPICE_PROTOCOL_MIN_VER,[0.14.2]))dnl
|
|
||||||
m4_define([SPICE_PROTOCOL_MIN_VER],m4_if(m4_version_compare(SPICE_PROTOCOL_MIN_VER,[0.14.2]),[1],SPICE_PROTOCOL_MIN_VER,[0.14.2]))dnl
|
|
||||||
[SPICE_PROTOCOL_MIN_VER]=SPICE_PROTOCOL_MIN_VER
|
|
||||||
m4_undefine([SPICE_PROTOCOL_MIN_VER])dnl
|
|
||||||
PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER])
|
|
||||||
AC_SUBST([SPICE_PROTOCOL_MIN_VER])dnl
|
|
||||||
dnl Get the required GLib2 version
|
|
||||||
m4_define([GLIB2_MIN_VER],m4_ifdef([GLIB2_MIN_VER],GLIB2_MIN_VER,[2.38]))dnl
|
|
||||||
m4_define([GLIB2_MIN_VER],m4_if(m4_version_compare(GLIB2_MIN_VER,[2.38]),[1],GLIB2_MIN_VER,[2.38]))dnl
|
|
||||||
m4_define([GLIB2_MIN_VERSION],[GLIB_VERSION_]m4_translit(GLIB2_MIN_VER,[.],[_]))dnl
|
|
||||||
[GLIB2_MIN_VER]=GLIB2_MIN_VER
|
|
||||||
[GLIB2_MIN_VERSION]=GLIB2_MIN_VERSION
|
|
||||||
m4_undefine([GLIB2_MIN_VER])dnl
|
|
||||||
m4_undefine([GLIB2_MIN_VERSION])dnl
|
|
||||||
PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= $GLIB2_MIN_VER gio-2.0 >= $GLIB2_MIN_VER])
|
|
||||||
dnl Configuration variables
|
|
||||||
AC_CONFIG_SUBDIRS([$1])dnl
|
|
||||||
SPICE_COMMON_CFLAGS='-I${top_srcdir}/$1 -I${top_builddir}/$1 -DG_LOG_DOMAIN=\"Spice\" $(SPICE_PROTOCOL_CFLAGS) $(GLIB2_CFLAGS)'
|
|
||||||
AC_SUBST([SPICE_COMMON_CFLAGS])dnl
|
|
||||||
|
|
||||||
SPICE_COMMON_DIR='${top_builddir}/$1'
|
|
||||||
AC_SUBST([SPICE_COMMON_DIR])dnl
|
|
||||||
])
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
dnl SPICE_MANUAL
|
|
||||||
dnl ------------
|
|
||||||
dnl Check if user wants manuals to be compiled and
|
|
||||||
dnl if all programs (asciidoc and a2x) are available
|
|
||||||
dnl ------------
|
|
||||||
dnl Shell defines:
|
|
||||||
dnl - have_asciidoc yes or not is asciidoc program is available
|
|
||||||
dnl Automake macros:
|
|
||||||
dnl - A2X a2x program or empty
|
|
||||||
dnl - ASCIIDOC asciidoc program or emtpy
|
|
||||||
dnl - BUILD_MANUAL if asciidoc and a2x are available
|
|
||||||
dnl - BUILD_HTML_MANUAL if asciidoc is available (html can be produced)
|
|
||||||
dnl - BUILD_CHUNKED_MANUAL if a2x is available
|
|
||||||
AC_DEFUN([SPICE_MANUAL],[
|
|
||||||
AC_ARG_ENABLE([manual],
|
|
||||||
AS_HELP_STRING([--enable-manual=@<:@auto/yes/no@:>@],
|
|
||||||
[Build SPICE manual]),
|
|
||||||
[],
|
|
||||||
[enable_manual="auto"])
|
|
||||||
if test "x$enable_manual" != "xno"; then
|
|
||||||
AC_PATH_PROG([ASCIIDOC], [asciidoc])
|
|
||||||
AS_IF([test -z "$ASCIIDOC" && test "x$enable_manual" = "xyes"],
|
|
||||||
[AC_MSG_ERROR([asciidoc is missing and build of manual was requested])])
|
|
||||||
AC_PATH_PROG([A2X], [a2x])
|
|
||||||
AS_IF([test -z "$A2X" && test "x$enable_manual" = "xyes"],
|
|
||||||
[AC_MSG_ERROR([a2x is missing and build of manual was requested])])
|
|
||||||
fi
|
|
||||||
AS_IF([test -n "$ASCIIDOC"], [have_asciidoc=yes], [have_asciidoc=no])
|
|
||||||
AM_CONDITIONAL([BUILD_MANUAL], [test -n "$ASCIIDOC" || test -n "$A2X"])
|
|
||||||
AM_CONDITIONAL([BUILD_HTML_MANUAL], [test -n "$ASCIIDOC"])
|
|
||||||
AM_CONDITIONAL([BUILD_CHUNKED_MANUAL], [test -n "$A2X"])
|
|
||||||
])
|
|
||||||
181
meson.build
181
meson.build
@ -1,181 +0,0 @@
|
|||||||
#
|
|
||||||
# project definition
|
|
||||||
#
|
|
||||||
project('spice-common', 'c',
|
|
||||||
meson_version : '>= 0.49.0',
|
|
||||||
license : 'LGPLv2.1',
|
|
||||||
default_options : ['warning_level=2'])
|
|
||||||
|
|
||||||
if not meson.is_subproject()
|
|
||||||
warning('This project is only intended to be used as a subproject!')
|
|
||||||
endif
|
|
||||||
|
|
||||||
# some global vars
|
|
||||||
spice_common_global_cflags = ['-DG_LOG_DOMAIN="Spice"',
|
|
||||||
'-Wno-unused-parameter']
|
|
||||||
|
|
||||||
if get_option('alignment-checks')
|
|
||||||
spice_common_global_cflags += ['-DSPICE_DEBUG_ALIGNMENT']
|
|
||||||
endif
|
|
||||||
|
|
||||||
spice_common_deps = []
|
|
||||||
spice_common_include = include_directories('.')
|
|
||||||
|
|
||||||
spice_proto = files('spice.proto')
|
|
||||||
spice_codegen = files('spice_codegen.py')
|
|
||||||
spice_codegen_files = [spice_codegen]
|
|
||||||
|
|
||||||
compiler = meson.get_compiler('c')
|
|
||||||
spice_common_config_data = configuration_data()
|
|
||||||
if get_option('extra-checks')
|
|
||||||
spice_common_config_data.set('ENABLE_EXTRA_CHECKS', '1')
|
|
||||||
endif
|
|
||||||
if host_machine.endian() == 'big'
|
|
||||||
spice_common_config_data.set('WORDS_BIGENDIAN', '1')
|
|
||||||
endif
|
|
||||||
|
|
||||||
if get_option('instrumentation') == 'recorder'
|
|
||||||
spice_common_config_data.set('ENABLE_RECORDER', '1')
|
|
||||||
endif
|
|
||||||
if get_option('instrumentation') == 'agent'
|
|
||||||
spice_common_config_data.set('ENABLE_AGENT_INTERFACE', '1')
|
|
||||||
endif
|
|
||||||
|
|
||||||
spice_common_generate_code = get_option('generate-code')
|
|
||||||
spice_common_generate_client_code = spice_common_generate_code == 'all' or spice_common_generate_code == 'client'
|
|
||||||
spice_common_generate_server_code = spice_common_generate_code == 'all' or spice_common_generate_code == 'server'
|
|
||||||
|
|
||||||
#
|
|
||||||
# check for system headers
|
|
||||||
#
|
|
||||||
headers = ['alloca.h',
|
|
||||||
'arpa/inet.h',
|
|
||||||
'dlfcn.h',
|
|
||||||
'inttypes.h',
|
|
||||||
'netinet/in.h',
|
|
||||||
'stdlib.h',
|
|
||||||
'sys/socket.h',
|
|
||||||
'sys/stat.h',
|
|
||||||
'sys/types.h',
|
|
||||||
'unistd.h',
|
|
||||||
'regex.h',
|
|
||||||
'sys/mman.h']
|
|
||||||
|
|
||||||
foreach header : headers
|
|
||||||
if compiler.has_header(header)
|
|
||||||
spice_common_config_data.set('HAVE_@0@'.format(header.underscorify().to_upper()), '1')
|
|
||||||
endif
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
#
|
|
||||||
# check for system functions
|
|
||||||
#
|
|
||||||
functions = ['alloca',
|
|
||||||
'sigaction',
|
|
||||||
'drand48',
|
|
||||||
'setlinebuf']
|
|
||||||
|
|
||||||
foreach func : functions
|
|
||||||
if compiler.has_function(func)
|
|
||||||
spice_common_config_data.set('HAVE_@0@'.format(func.underscorify().to_upper()), '1')
|
|
||||||
endif
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
# FIXME
|
|
||||||
# check for libm, as workaround for https://github.com/mesonbuild/meson/issues/3740
|
|
||||||
libm = compiler.find_library('m', required : false)
|
|
||||||
if libm.found()
|
|
||||||
spice_common_deps += libm
|
|
||||||
endif
|
|
||||||
|
|
||||||
#
|
|
||||||
# check for mandatory dependencies
|
|
||||||
#
|
|
||||||
glib_version = '2.38'
|
|
||||||
glib_version_info = '>= @0@'.format(glib_version)
|
|
||||||
|
|
||||||
spice_protocol_version = '0.14.2'
|
|
||||||
|
|
||||||
spice_protocol_version_req = get_option('spice-protocol-version')
|
|
||||||
if spice_protocol_version_req.version_compare('> @0@'.format(spice_protocol_version))
|
|
||||||
spice_protocol_version = spice_protocol_version_req
|
|
||||||
endif
|
|
||||||
|
|
||||||
deps = {'spice-protocol' : '>= @0@'.format(spice_protocol_version),
|
|
||||||
'glib-2.0' : glib_version_info,
|
|
||||||
'pixman-1' : '>= 0.17.7',
|
|
||||||
'openssl' : '>= 1.0.0'}
|
|
||||||
|
|
||||||
foreach dep, version : deps
|
|
||||||
spice_common_deps += dependency(dep, version : version)
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
gio2_deps = dependency('gio-2.0', version : glib_version_info)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Non-mandatory/optional dependencies
|
|
||||||
#
|
|
||||||
optional_deps = {'opus' : '>= 0.9.14'}
|
|
||||||
foreach dep, version : optional_deps
|
|
||||||
d = dependency(dep, required : get_option(dep), version : version)
|
|
||||||
if d.found()
|
|
||||||
spice_common_deps += d
|
|
||||||
spice_common_config_data.set('HAVE_@0@'.format(dep.underscorify().to_upper()), '1')
|
|
||||||
endif
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
# Python
|
|
||||||
if spice_common_generate_client_code or spice_common_generate_server_code
|
|
||||||
py_module = import('python')
|
|
||||||
python = py_module.find_installation('python3')
|
|
||||||
|
|
||||||
if get_option('python-checks')
|
|
||||||
foreach module : ['pyparsing']
|
|
||||||
message('Checking for python module @0@'.format(module))
|
|
||||||
cmd = run_command(python, '-c', 'import @0@'.format(module), check : false)
|
|
||||||
if cmd.returncode() != 0
|
|
||||||
error('Python module @0@ not found'.format(module))
|
|
||||||
endif
|
|
||||||
endforeach
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
# smartcard check
|
|
||||||
smartcard_dep = dependency('libcacard', required : get_option('smartcard'), version : '>= 2.5.1')
|
|
||||||
if smartcard_dep.found()
|
|
||||||
spice_common_deps += smartcard_dep
|
|
||||||
spice_common_config_data.set('USE_SMARTCARD', '1')
|
|
||||||
endif
|
|
||||||
|
|
||||||
# udev check
|
|
||||||
udev_dep = dependency('libudev', required : false)
|
|
||||||
if udev_dep.found()
|
|
||||||
spice_common_deps += udev_dep
|
|
||||||
spice_common_config_data.set('HAVE_UDEV', '1')
|
|
||||||
endif
|
|
||||||
|
|
||||||
#
|
|
||||||
# global C defines
|
|
||||||
#
|
|
||||||
glib_encoded_version = 'GLIB_VERSION_@0@'.format(glib_version.underscorify())
|
|
||||||
spice_common_global_cflags += ['-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_encoded_version),
|
|
||||||
'-DGLIB_VERSION_MAX_ALLOWED=@0@'.format(glib_encoded_version)]
|
|
||||||
|
|
||||||
add_project_arguments(compiler.get_supported_arguments(spice_common_global_cflags),
|
|
||||||
language : 'c')
|
|
||||||
|
|
||||||
#
|
|
||||||
# Subdirectories
|
|
||||||
#
|
|
||||||
subdir('python_modules')
|
|
||||||
subdir('common')
|
|
||||||
if get_option('tests')
|
|
||||||
subdir('tests')
|
|
||||||
endif
|
|
||||||
subdir('docs')
|
|
||||||
|
|
||||||
#
|
|
||||||
# write config.h
|
|
||||||
#
|
|
||||||
configure_file(output : 'config.h',
|
|
||||||
configuration : spice_common_config_data)
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user