mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-common
synced 2025-12-26 22:55:35 +00:00
Compare commits
No commits in common. "before-split" and "master" have entirely different histories.
before-spl
...
master
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,9 +0,0 @@
|
|||||||
*.la
|
|
||||||
*.lo
|
|
||||||
*.loT
|
|
||||||
*.o
|
|
||||||
.deps
|
|
||||||
.dirstamp
|
|
||||||
.libs
|
|
||||||
Makefile
|
|
||||||
Makefile.in
|
|
||||||
52
.gitlab-ci.yml
Normal file
52
.gitlab-ci.yml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
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
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "common/recorder"]
|
||||||
|
path = common/recorder
|
||||||
|
url = https://github.com/c3d/recorder.git
|
||||||
3
.gitpublish
Normal file
3
.gitpublish
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[gitpublishprofile "default"]
|
||||||
|
to = spice-devel@lists.freedesktop.org
|
||||||
|
prefix = PATCH spice-common
|
||||||
502
COPYING
Normal file
502
COPYING
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
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!
|
||||||
95
Makefile.am
95
Makefile.am
@ -1,76 +1,33 @@
|
|||||||
if OS_WIN32
|
|
||||||
SUBDIRS = win
|
|
||||||
endif
|
|
||||||
|
|
||||||
NULL =
|
NULL =
|
||||||
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libspice-common.la
|
SUBDIRS = python_modules common docs
|
||||||
libspice_common_la_SOURCES = \
|
|
||||||
bitops.h \
|
|
||||||
canvas_utils.c \
|
|
||||||
canvas_utils.h \
|
|
||||||
draw.h \
|
|
||||||
lines.c \
|
|
||||||
lines.h \
|
|
||||||
lz.c \
|
|
||||||
lz.h \
|
|
||||||
lz_common.h \
|
|
||||||
lz_config.h \
|
|
||||||
marshaller.c \
|
|
||||||
marshaller.h \
|
|
||||||
mem.c \
|
|
||||||
mem.h \
|
|
||||||
messages.h \
|
|
||||||
mutex.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 \
|
|
||||||
spice_common.h \
|
|
||||||
ssl_verify.c \
|
|
||||||
ssl_verify.h \
|
|
||||||
backtrace.c \
|
|
||||||
backtrace.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
if SUPPORT_GL
|
if ENABLE_TESTS
|
||||||
libspice_common_la_SOURCES += \
|
SUBDIRS += tests
|
||||||
gl_utils.h \
|
|
||||||
glc.h \
|
|
||||||
glc.c \
|
|
||||||
ogl_ctx.h \
|
|
||||||
ogl_ctx.c \
|
|
||||||
$(NULL)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
INCLUDES = \
|
|
||||||
$(GL_CFLAGS) \
|
|
||||||
$(PIXMAN_CFLAGS) \
|
|
||||||
$(PROTOCOL_CFLAGS) \
|
|
||||||
$(VISIBILITY_HIDDEN_CFLAGS) \
|
|
||||||
$(WARN_CFLAGS) \
|
|
||||||
-std=gnu99 \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
canvas_base.c \
|
meson.build \
|
||||||
canvas_base.h \
|
meson_options.txt \
|
||||||
gdi_canvas.c \
|
spice_codegen.py \
|
||||||
gdi_canvas.h \
|
spice.proto \
|
||||||
gl_canvas.c \
|
|
||||||
gl_canvas.h \
|
|
||||||
sw_canvas.c \
|
|
||||||
sw_canvas.h \
|
|
||||||
lz_compress_tmpl.c \
|
|
||||||
lz_decompress_tmpl.c \
|
|
||||||
quic_family_tmpl.c \
|
|
||||||
quic_rgb_tmpl.c \
|
|
||||||
quic_tmpl.c \
|
|
||||||
$(NULL)
|
$(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
Executable file
17
autogen.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/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
|
||||||
91
bitops.h
91
bitops.h
@ -1,91 +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, 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
|
|
||||||
299
canvas_utils.c
299
canvas_utils.c
@ -1,299 +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/>.
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "canvas_utils.h"
|
|
||||||
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
#include "mem.h"
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
static int gdi_handlers = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CANVAS_ERROR
|
|
||||||
#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;
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
if (data->bitmap) {
|
|
||||||
DeleteObject((HBITMAP)data->bitmap);
|
|
||||||
CloseHandle(data->mutex);
|
|
||||||
gdi_handlers--;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
free(data->data);
|
|
||||||
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PixmanData *
|
|
||||||
pixman_image_add_data(pixman_image_t *image)
|
|
||||||
{
|
|
||||||
PixmanData *data;
|
|
||||||
|
|
||||||
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
|
||||||
if (data == NULL) {
|
|
||||||
data = (PixmanData *)calloc(1, sizeof(PixmanData));
|
|
||||||
if (data == NULL) {
|
|
||||||
CANVAS_ERROR("out of memory");
|
|
||||||
}
|
|
||||||
pixman_image_set_destroy_function(image,
|
|
||||||
release_data,
|
|
||||||
data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
spice_pixman_image_set_format(pixman_image_t *image,
|
|
||||||
pixman_format_code_t format)
|
|
||||||
{
|
|
||||||
PixmanData *data;
|
|
||||||
|
|
||||||
data = pixman_image_add_data(image);
|
|
||||||
data->format = format;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixman_format_code_t
|
|
||||||
spice_pixman_image_get_format(pixman_image_t *image)
|
|
||||||
{
|
|
||||||
PixmanData *data;
|
|
||||||
|
|
||||||
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
|
||||||
if (data != NULL &&
|
|
||||||
data->format != 0)
|
|
||||||
return data->format;
|
|
||||||
|
|
||||||
CANVAS_ERROR("Unknown pixman image type");
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t format, int width, int height,
|
|
||||||
int stride)
|
|
||||||
{
|
|
||||||
uint8_t *data;
|
|
||||||
uint8_t *stride_data;
|
|
||||||
pixman_image_t *surface;
|
|
||||||
PixmanData *pixman_data;
|
|
||||||
|
|
||||||
data = (uint8_t *)spice_malloc_n(abs(stride), height);
|
|
||||||
if (stride < 0) {
|
|
||||||
stride_data = data + (-stride) * (height - 1);
|
|
||||||
} else {
|
|
||||||
stride_data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
surface = pixman_image_create_bits(format, width, height, (uint32_t *)stride_data, stride);
|
|
||||||
|
|
||||||
if (surface == NULL) {
|
|
||||||
free(data);
|
|
||||||
CANVAS_ERROR("create surface failed, out of memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
pixman_data = pixman_image_add_data(surface);
|
|
||||||
pixman_data->data = data;
|
|
||||||
pixman_data->format = format;
|
|
||||||
|
|
||||||
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)
|
|
||||||
#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) {
|
|
||||||
pixman_image_t *surface;
|
|
||||||
PixmanData *data;
|
|
||||||
|
|
||||||
surface = pixman_image_create_bits(format, width, height, NULL, 0);
|
|
||||||
data = pixman_image_add_data(surface);
|
|
||||||
data->format = format;
|
|
||||||
return surface;
|
|
||||||
} else {
|
|
||||||
// NOTE: we assume here that the lz decoders always decode to RGB32.
|
|
||||||
int stride = 0;
|
|
||||||
switch (format) {
|
|
||||||
case PIXMAN_a8r8g8b8:
|
|
||||||
case PIXMAN_x8r8g8b8:
|
|
||||||
stride = width * 4;
|
|
||||||
break;
|
|
||||||
case PIXMAN_x1r5g5b5:
|
|
||||||
case PIXMAN_r5g6b5:
|
|
||||||
stride = SPICE_ALIGN(width * 2, 4);
|
|
||||||
break;
|
|
||||||
case PIXMAN_a8:
|
|
||||||
stride = SPICE_ALIGN(width, 4);
|
|
||||||
break;
|
|
||||||
case PIXMAN_a1:
|
|
||||||
stride = SPICE_ALIGN(width, 32) / 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
CANVAS_ERROR("invalid format");
|
|
||||||
}
|
|
||||||
stride = -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_format_code_t pixman_format, int width,
|
|
||||||
int height, int gross_pixels, int top_down)
|
|
||||||
{
|
|
||||||
int stride;
|
|
||||||
pixman_image_t *surface = NULL;
|
|
||||||
|
|
||||||
stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);
|
|
||||||
|
|
||||||
if (!top_down) {
|
|
||||||
stride = -stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
surface = surface_create_stride(
|
|
||||||
#ifdef WIN32
|
|
||||||
canvas_data->dc,
|
|
||||||
#endif
|
|
||||||
pixman_format, width, height, stride);
|
|
||||||
canvas_data->out_surface = surface;
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
161
common/Makefile.am
Normal file
161
common/Makefile.am
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
NULL =
|
||||||
|
|
||||||
|
# Avoid need for python(pyparsing) by end users
|
||||||
|
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 = \
|
||||||
|
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 \
|
||||||
|
udev.c \
|
||||||
|
udev.h \
|
||||||
|
utils.c \
|
||||||
|
utils.h \
|
||||||
|
verify.h \
|
||||||
|
recorder.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
if ENABLE_RECORDER
|
||||||
|
libspice_common_la_SOURCES += \
|
||||||
|
recorder/recorder.c \
|
||||||
|
recorder/recorder.h \
|
||||||
|
recorder/recorder_ring.c \
|
||||||
|
recorder/recorder_ring.h \
|
||||||
|
$(NULL)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ENABLE_AGENT_INTERFACE
|
||||||
|
libspice_common_la_SOURCES += \
|
||||||
|
agent_interface.c \
|
||||||
|
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) \
|
||||||
|
$(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 = \
|
||||||
|
$(CLIENT_MARSHALLERS) \
|
||||||
|
$(SERVER_MARSHALLERS) \
|
||||||
|
generated_messages.h \
|
||||||
|
meson.build \
|
||||||
|
canvas_base.c \
|
||||||
|
canvas_base.h \
|
||||||
|
lz_compress_tmpl.c \
|
||||||
|
lz_decompress_tmpl.c \
|
||||||
|
quic_family_tmpl.c \
|
||||||
|
quic_tmpl.c \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
GITIGNOREFILES = \
|
||||||
|
generated_messages.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
||||||
361
common/agent.c
Normal file
361
common/agent.c
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
/* -*- 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);
|
||||||
|
}
|
||||||
83
common/agent.h
Normal file
83
common/agent.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/* -*- 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
|
||||||
510
common/agent_interface.c
Normal file
510
common/agent_interface.c
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
/* -*- 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);
|
||||||
|
}
|
||||||
564
common/agent_interface.h
Normal file
564
common/agent_interface.h
Normal file
@ -0,0 +1,564 @@
|
|||||||
|
#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,18 +22,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
#if !defined(WIN32) || defined(__MINGW32__)
|
||||||
#include <stdio.h>
|
|
||||||
|
#include "backtrace.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.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
|
||||||
@ -75,7 +77,6 @@ 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);
|
||||||
@ -131,3 +132,4 @@ 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 BACKTRACE_H
|
#ifndef H_SPICE_COMMON_BACKTRACE
|
||||||
#define BACKTRACE_H
|
#define H_SPICE_COMMON_BACKTRACE
|
||||||
|
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
@ -31,4 +31,4 @@ void spice_backtrace(void);
|
|||||||
|
|
||||||
SPICE_END_DECLS
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#endif // BACKTRACE_H
|
#endif // H_SPICE_COMMON_BACKTRACE
|
||||||
File diff suppressed because it is too large
Load Diff
@ -16,24 +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_CANVAS_BASE
|
#ifndef H_SPICE_COMMON_CANVAS_BASE
|
||||||
#define _H_CANVAS_BASE
|
#define H_SPICE_COMMON_CANVAS_BASE
|
||||||
|
|
||||||
#ifndef SPICE_CANVAS_INTERNAL
|
#include <spice/macros.h>
|
||||||
#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
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void (*spice_destroy_fn_t)(void *data);
|
typedef void (*spice_destroy_fn_t)(void *data);
|
||||||
|
|
||||||
@ -64,7 +57,7 @@ typedef struct {
|
|||||||
} SpiceImageCacheOps;
|
} SpiceImageCacheOps;
|
||||||
|
|
||||||
struct _SpiceImageCache {
|
struct _SpiceImageCache {
|
||||||
SpiceImageCacheOps *ops;
|
const SpiceImageCacheOps *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -73,7 +66,7 @@ typedef struct {
|
|||||||
} SpiceImageSurfacesOps;
|
} SpiceImageSurfacesOps;
|
||||||
|
|
||||||
struct _SpiceImageSurfaces {
|
struct _SpiceImageSurfaces {
|
||||||
SpiceImageSurfacesOps *ops;
|
const SpiceImageSurfacesOps *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -137,6 +130,7 @@ 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);
|
||||||
@ -144,9 +138,6 @@ 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);
|
||||||
@ -310,18 +301,13 @@ 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);
|
pixman_image_t *(*get_image)(SpiceCanvas *canvas, int force_opaque);
|
||||||
} 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
180
common/canvas_utils.c
Normal file
180
common/canvas_utils.c
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
/* -*- 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 <config.h>
|
||||||
|
|
||||||
|
#include "canvas_utils.h"
|
||||||
|
#include "mem.h"
|
||||||
|
|
||||||
|
typedef struct PixmanData {
|
||||||
|
uint8_t *data;
|
||||||
|
pixman_format_code_t format;
|
||||||
|
} PixmanData;
|
||||||
|
|
||||||
|
static void release_data(SPICE_GNUC_UNUSED pixman_image_t *image,
|
||||||
|
void *release_data)
|
||||||
|
{
|
||||||
|
PixmanData *data = (PixmanData *)release_data;
|
||||||
|
|
||||||
|
free(data->data);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PixmanData *
|
||||||
|
pixman_image_add_data(pixman_image_t *image)
|
||||||
|
{
|
||||||
|
PixmanData *data;
|
||||||
|
|
||||||
|
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
||||||
|
if (data == NULL) {
|
||||||
|
data = (PixmanData *)calloc(1, sizeof(PixmanData));
|
||||||
|
if (data == NULL) {
|
||||||
|
spice_error("out of memory");
|
||||||
|
}
|
||||||
|
pixman_image_set_destroy_function(image,
|
||||||
|
release_data,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
spice_pixman_image_set_format(pixman_image_t *image,
|
||||||
|
pixman_format_code_t format)
|
||||||
|
{
|
||||||
|
PixmanData *data;
|
||||||
|
|
||||||
|
data = pixman_image_add_data(image);
|
||||||
|
data->format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format)
|
||||||
|
{
|
||||||
|
PixmanData *data;
|
||||||
|
|
||||||
|
spice_return_val_if_fail(format != NULL, 0);
|
||||||
|
|
||||||
|
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
||||||
|
if (data != NULL && data->format != 0) {
|
||||||
|
*format = data->format;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
spice_warn_if_reached();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
||||||
|
int stride)
|
||||||
|
{
|
||||||
|
uint8_t *data;
|
||||||
|
uint8_t *stride_data;
|
||||||
|
pixman_image_t *surface;
|
||||||
|
PixmanData *pixman_data;
|
||||||
|
|
||||||
|
data = (uint8_t *)spice_malloc_n(abs(stride), height);
|
||||||
|
if (stride < 0) {
|
||||||
|
stride_data = data + (-stride) * (height - 1);
|
||||||
|
} else {
|
||||||
|
stride_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface = pixman_image_create_bits(format, width, height, (uint32_t *)stride_data, stride);
|
||||||
|
|
||||||
|
if (surface == NULL) {
|
||||||
|
free(data);
|
||||||
|
data = NULL;
|
||||||
|
spice_error("create surface failed, out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_data = pixman_image_add_data(surface);
|
||||||
|
pixman_data->data = data;
|
||||||
|
pixman_data->format = format;
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
|
||||||
|
{
|
||||||
|
if (top_down) {
|
||||||
|
pixman_image_t *surface;
|
||||||
|
PixmanData *data;
|
||||||
|
|
||||||
|
surface = pixman_image_create_bits(format, width, height, NULL, 0);
|
||||||
|
data = pixman_image_add_data(surface);
|
||||||
|
data->format = format;
|
||||||
|
return surface;
|
||||||
|
} else {
|
||||||
|
// NOTE: we assume here that the lz decoders always decode to RGB32.
|
||||||
|
int stride = 0;
|
||||||
|
switch (format) {
|
||||||
|
case PIXMAN_a8r8g8b8:
|
||||||
|
case PIXMAN_x8r8g8b8:
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
case PIXMAN_b8g8r8a8:
|
||||||
|
case PIXMAN_b8g8r8x8:
|
||||||
|
#endif
|
||||||
|
stride = width * 4;
|
||||||
|
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_r5g6b5:
|
||||||
|
stride = SPICE_ALIGN(width * 2, 4);
|
||||||
|
break;
|
||||||
|
case PIXMAN_a8:
|
||||||
|
stride = SPICE_ALIGN(width, 4);
|
||||||
|
break;
|
||||||
|
case PIXMAN_a1:
|
||||||
|
stride = SPICE_ALIGN(width, 32) / 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
spice_error("invalid format");
|
||||||
|
}
|
||||||
|
stride = -stride;
|
||||||
|
return surface_create_stride(format, width, height, stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
||||||
|
pixman_format_code_t pixman_format, int width,
|
||||||
|
int height, int gross_pixels, int top_down)
|
||||||
|
{
|
||||||
|
int stride;
|
||||||
|
pixman_image_t *surface = NULL;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
stride = -stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface = surface_create_stride(pixman_format, width, height, stride);
|
||||||
|
canvas_data->out_surface = surface;
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
@ -16,56 +16,29 @@
|
|||||||
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_CANVAS_UTILS
|
#ifndef H_SPICE_COMMON_CANVAS_UTILS
|
||||||
#define _H_CANVAS_UTILS
|
#define H_SPICE_COMMON_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"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
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);
|
||||||
pixman_format_code_t spice_pixman_image_get_format(pixman_image_t *image);
|
int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format);
|
||||||
|
|
||||||
|
|
||||||
#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;
|
||||||
|
|
||||||
@ -73,8 +46,7 @@ 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,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) 2009 Red Hat, Inc.
|
Copyright (C) 2010 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,23 +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_GLCTX
|
#ifndef H_SPICE_COMMON_CLIENT_MARSHALLERS
|
||||||
#define _H_GLCTX
|
#define H_SPICE_COMMON_CLIENT_MARSHALLERS
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include <spice/protocol.h>
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct OGLCtx OGLCtx;
|
#include "messages.h"
|
||||||
|
#include "common/generated_client_marshallers.h"
|
||||||
|
#include "marshaller.h"
|
||||||
|
|
||||||
const char *oglctx_type_str(OGLCtx *ctx);
|
SPICE_BEGIN_DECLS
|
||||||
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);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SpiceMessageMarshallers *spice_message_marshallers_get(void);
|
||||||
}
|
|
||||||
#endif
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
38
common/demarshallers.h
Normal file
38
common/demarshallers.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
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,16 +28,15 @@
|
|||||||
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_DRAW
|
#ifndef H_SPICE_COMMON_DRAW
|
||||||
#define _H_SPICE_DRAW
|
#define H_SPICE_COMMON_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"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
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))
|
||||||
@ -83,7 +82,7 @@ typedef struct SpiceClipRects {
|
|||||||
} SpiceClipRects;
|
} SpiceClipRects;
|
||||||
|
|
||||||
typedef struct SpiceClip {
|
typedef struct SpiceClip {
|
||||||
uint32_t type;
|
uint8_t type;
|
||||||
SpiceClipRects *rects;
|
SpiceClipRects *rects;
|
||||||
} SpiceClip;
|
} SpiceClip;
|
||||||
|
|
||||||
@ -121,7 +120,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;
|
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData, SpiceLZ4Data;
|
||||||
|
|
||||||
typedef struct SpiceLZPLTData {
|
typedef struct SpiceLZPLTData {
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
@ -154,6 +153,7 @@ 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,6 +224,26 @@ 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;
|
||||||
@ -274,8 +294,12 @@ typedef struct SpiceCursorHeader {
|
|||||||
uint16_t hot_spot_y;
|
uint16_t hot_spot_y;
|
||||||
} SpiceCursorHeader;
|
} SpiceCursorHeader;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
static inline int spice_image_descriptor_is_lossy(const SpiceImageDescriptor *descriptor)
|
||||||
|
{
|
||||||
|
return descriptor->type == SPICE_IMAGE_TYPE_JPEG ||
|
||||||
|
descriptor->type == SPICE_IMAGE_TYPE_JPEG_ALPHA;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _H_SPICE_DRAW */
|
SPICE_END_DECLS
|
||||||
|
|
||||||
|
#endif // H_SPICE_COMMON_DRAW
|
||||||
@ -45,9 +45,7 @@ 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>
|
||||||
@ -84,7 +82,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;
|
||||||
@ -412,7 +410,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 <= dist)
|
if (totallen > 0 && totallen <= dist)
|
||||||
dist = dist % totallen;
|
dist = dist % totallen;
|
||||||
while (dist >= pDash[dashIndex]) {
|
while (dist >= pDash[dashIndex]) {
|
||||||
dist -= pDash[dashIndex];
|
dist -= pDash[dashIndex];
|
||||||
@ -806,14 +804,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;
|
||||||
}
|
}
|
||||||
@ -836,8 +834,6 @@ 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);
|
||||||
@ -929,7 +925,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
|
||||||
@ -977,7 +973,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
|
||||||
@ -1023,7 +1019,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
|
||||||
@ -1068,7 +1064,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
|
||||||
@ -1113,7 +1109,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)
|
||||||
@ -1826,7 +1822,7 @@ miFillRectPolyHelper (GCPtr pGC, Boolean foreground, SpanDataPtr spanData, int x
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
miPolyBuildEdge (double x0, double y0, double k, /* x0 * dy - y0 * dx */
|
miPolyBuildEdge (SPICE_GNUC_UNUSED 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;
|
||||||
@ -1837,15 +1833,6 @@ miPolyBuildEdge (double x0, double y0, double k, /* x0 * dy - y0 * dx */
|
|||||||
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;
|
||||||
|
|
||||||
@ -1970,7 +1957,11 @@ miPolyBuildPoly (PolyVertexPtr vertices,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
miLineOnePoint (GCPtr pGC, Boolean foreground, SpanDataPtr spanData, int x, int y)
|
miLineOnePoint (GCPtr pGC,
|
||||||
|
Boolean foreground,
|
||||||
|
SPICE_GNUC_UNUSED SpanDataPtr spanData,
|
||||||
|
int x,
|
||||||
|
int y)
|
||||||
{
|
{
|
||||||
DDXPointRec pt;
|
DDXPointRec pt;
|
||||||
int wid;
|
int wid;
|
||||||
@ -2430,7 +2421,7 @@ miLineArc (GCPtr pGC,
|
|||||||
int xorgi = 0, yorgi = 0;
|
int xorgi = 0, yorgi = 0;
|
||||||
Spans spanRec;
|
Spans spanRec;
|
||||||
int n;
|
int n;
|
||||||
PolyEdgeRec edge1, edge2;
|
PolyEdgeRec edge1 = { 0 }, edge2 = { 0 };
|
||||||
int edgey1, edgey2;
|
int edgey1, edgey2;
|
||||||
Boolean edgeleft1, edgeleft2;
|
Boolean edgeleft1, edgeleft2;
|
||||||
|
|
||||||
@ -2501,13 +2492,18 @@ miLineArc (GCPtr pGC,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
miLineProjectingCap (GCPtr pGC, Boolean foreground,
|
miLineProjectingCap (GCPtr pGC,
|
||||||
SpanDataPtr spanData, LineFacePtr face, Boolean isLeft,
|
Boolean foreground,
|
||||||
double xorg, double yorg, Boolean isInt)
|
SpanDataPtr spanData,
|
||||||
|
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[2], rights[2];
|
PolyEdgeRec lefts[4], rights[4];
|
||||||
int lefty, righty, topy, bottomy;
|
int lefty, righty, topy, bottomy;
|
||||||
PolyEdgePtr left, right;
|
PolyEdgePtr left, right;
|
||||||
PolyEdgePtr top, bottom;
|
PolyEdgePtr top, bottom;
|
||||||
@ -2665,7 +2661,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[2], rights[2];
|
PolyEdgeRec lefts[4], rights[4];
|
||||||
LineFacePtr tface;
|
LineFacePtr tface;
|
||||||
int lw = pGC->lineWidth;
|
int lw = pGC->lineWidth;
|
||||||
|
|
||||||
@ -2980,9 +2976,9 @@ miWideDashSegment (GCPtr pGC,
|
|||||||
double L, l;
|
double L, l;
|
||||||
double k;
|
double k;
|
||||||
PolyVertexRec vertices[4];
|
PolyVertexRec vertices[4];
|
||||||
PolyVertexRec saveRight = { 0 }, saveBottom;
|
PolyVertexRec saveRight = { 0, 0 }, saveBottom;
|
||||||
PolySlopeRec slopes[4];
|
PolySlopeRec slopes[4];
|
||||||
PolyEdgeRec left[2], right[2];
|
PolyEdgeRec left[4], right[4];
|
||||||
LineFaceRec lcapFace, rcapFace;
|
LineFaceRec lcapFace, rcapFace;
|
||||||
int nleft, nright;
|
int nleft, nright;
|
||||||
int h;
|
int h;
|
||||||
@ -46,17 +46,17 @@ SOFTWARE.
|
|||||||
|
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
|
|
||||||
#ifndef LINES_H
|
#ifndef H_SPICE_COMMON_LINES
|
||||||
#define LINES_H
|
#define H_SPICE_COMMON_LINES
|
||||||
|
|
||||||
#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"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct lineGC lineGC;
|
typedef struct lineGC lineGC;
|
||||||
|
|
||||||
@ -131,8 +131,6 @@ extern int spice_canvas_clip_spans(pixman_region32_t *clip_region,
|
|||||||
int *new_widths,
|
int *new_widths,
|
||||||
int sorted);
|
int sorted);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LINES_H */
|
#endif // H_SPICE_COMMON_LINES
|
||||||
71
common/log.c
Normal file
71
common/log.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
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
Normal file
110
common/log.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
@ -43,29 +43,16 @@
|
|||||||
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 {
|
||||||
@ -102,7 +89,6 @@ 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;
|
||||||
@ -113,7 +99,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);
|
||||||
@ -121,7 +107,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;
|
||||||
|
|
||||||
@ -148,7 +134,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;
|
||||||
@ -184,7 +170,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;
|
||||||
|
|
||||||
ASSERT(encoder->usr, !encoder->head_image_segs);
|
spice_return_val_if_fail(!encoder->head_image_segs, FALSE);
|
||||||
|
|
||||||
image_seg = lz_alloc_image_seg(encoder);
|
image_seg = lz_alloc_image_seg(encoder);
|
||||||
if (!image_seg) {
|
if (!image_seg) {
|
||||||
@ -224,7 +210,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);
|
||||||
@ -234,20 +220,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__);
|
||||||
}
|
}
|
||||||
ASSERT(encoder->usr, encoder->io_now);
|
spice_return_if_fail(encoder->io_now);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
|
spice_return_if_fail(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);
|
||||||
@ -255,37 +241,32 @@ 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)
|
||||||
{
|
{
|
||||||
ASSERT(encoder->usr, encoder->io_last_copy);
|
spice_return_if_fail(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
|
||||||
ASSERT(encoder->usr, encoder->io_now == encoder->io_last_copy)
|
spice_return_if_fail(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)
|
||||||
{
|
{
|
||||||
ASSERT(encoder->usr, io_ptr <= io_ptr_end);
|
spice_return_val_if_fail(io_ptr <= io_ptr_end, FALSE);
|
||||||
|
|
||||||
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;
|
||||||
@ -293,20 +274,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__);
|
||||||
}
|
}
|
||||||
ASSERT(encoder->usr, encoder->io_now);
|
spice_assert(encoder->io_now);
|
||||||
}
|
}
|
||||||
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
|
spice_assert(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);
|
||||||
@ -319,7 +300,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;
|
||||||
@ -393,30 +374,23 @@ void lz_destroy(LzContext *lz)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#include <spice/start-packed.h>
|
||||||
#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 ATTR_PACKED one_byte_pixel_t {
|
typedef struct SPICE_ATTR_PACKED one_byte_pixel_t {
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
} one_byte_pixel_t;
|
} one_byte_pixel_t;
|
||||||
|
|
||||||
typedef struct ATTR_PACKED rgb32_pixel_t {
|
typedef struct SPICE_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 ATTR_PACKED rgb24_pixel_t {
|
typedef struct SPICE_ATTR_PACKED rgb24_pixel_t {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
@ -424,11 +398,7 @@ typedef struct ATTR_PACKED rgb24_pixel_t {
|
|||||||
|
|
||||||
typedef uint16_t rgb16_pixel_t;
|
typedef uint16_t rgb16_pixel_t;
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#include <spice/end-packed.h>
|
||||||
#pragma pack(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef ATTR_PACKED
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_COPY 32
|
#define MAX_COPY 32
|
||||||
@ -476,6 +446,13 @@ 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"
|
||||||
@ -504,6 +481,44 @@ 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)
|
||||||
@ -511,23 +526,7 @@ 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;
|
||||||
|
|
||||||
encoder->type = type;
|
lz_set_sizes(encoder, type, width, height, stride);
|
||||||
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)) {
|
||||||
@ -571,6 +570,9 @@ 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");
|
||||||
@ -610,10 +612,15 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->type = (LzImageType)decode_32(encoder);
|
int type = decode_32(encoder);
|
||||||
encoder->width = decode_32(encoder);
|
if (type <= LZ_IMAGE_TYPE_INVALID || type > LZ_IMAGE_TYPE_A8) {
|
||||||
encoder->height = decode_32(encoder);
|
encoder->usr->error(encoder->usr, "invalid lz type %d\n", type);
|
||||||
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;
|
||||||
@ -646,6 +653,7 @@ 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:
|
||||||
@ -707,7 +715,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);
|
||||||
ASSERT(encoder->usr, alpha_size == size);
|
spice_assert(alpha_size == size);
|
||||||
} else {
|
} else {
|
||||||
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
||||||
}
|
}
|
||||||
@ -720,6 +728,17 @@ 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:
|
||||||
@ -731,8 +750,8 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(encoder->usr, is_io_to_decode_end(encoder));
|
spice_assert(is_io_to_decode_end(encoder));
|
||||||
ASSERT(encoder->usr, out_size == size);
|
spice_assert(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");
|
||||||
@ -3,24 +3,26 @@
|
|||||||
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 __LZ_H
|
#ifndef H_SPICE_COMMON_LZ
|
||||||
#define __LZ_H
|
#define H_SPICE_COMMON_LZ
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void *LzContext;
|
typedef void *LzContext;
|
||||||
|
|
||||||
typedef struct LzUsrContext LzUsrContext;
|
typedef struct LzUsrContext LzUsrContext;
|
||||||
struct LzUsrContext {
|
struct LzUsrContext {
|
||||||
void (*error)(LzUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_NORETURN
|
||||||
void (*warn)(LzUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_PRINTF(2, 3) void (*error)(LzUsrContext *usr, const char *fmt, ...);
|
||||||
void (*info)(LzUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_PRINTF(2, 3) void (*warn)(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
|
||||||
@ -75,8 +77,6 @@ LzContext *lz_create(LzUsrContext *usr);
|
|||||||
|
|
||||||
void lz_destroy(LzContext *lz);
|
void lz_destroy(LzContext *lz);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // __LZ_H
|
#endif // H_SPICE_COMMON_LZ
|
||||||
@ -20,14 +20,13 @@
|
|||||||
|
|
||||||
/*common header for encoder and decoder*/
|
/*common header for encoder and decoder*/
|
||||||
|
|
||||||
#ifndef _LZ_COMMON_H
|
#ifndef H_SPICE_COMMON_LZ_COMMON
|
||||||
#define _LZ_COMMON_H
|
#define H_SPICE_COMMON_LZ_COMMON
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include <spice/macros.h>
|
||||||
extern "C" {
|
#include "verify.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
//#define DEBUG
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
/* 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)
|
||||||
@ -44,26 +43,30 @@ 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};
|
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_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
|
static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 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};
|
static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 1};
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
#define LZ_MAGIC (*(uint32_t *)"LZ ")
|
/* ASCII "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))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _LZ_COMMON_H
|
#endif // H_SPICE_COMMON_LZ_COMMON
|
||||||
@ -40,11 +40,9 @@
|
|||||||
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;}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -71,6 +69,21 @@
|
|||||||
}
|
}
|
||||||
#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
|
||||||
@ -90,9 +103,8 @@
|
|||||||
#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_r(pix) (((pix) >> 10) & 0x1f)
|
#define GET_rgb(pix) ((pix) & 0x7fffu)
|
||||||
#define GET_g(pix) (((pix) >> 5) & 0x1f)
|
#define SAME_PIXEL(p1, p2) (GET_rgb(p1) == GET_rgb(p2))
|
||||||
#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) { \
|
||||||
@ -110,20 +122,17 @@
|
|||||||
#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 GET_r(pix) ((pix).r)
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
||||||
#define GET_g(pix) ((pix).g)
|
#define SAME_PIXEL(p1, p2) ((p1).r == (p2).r && (p1).g == (p2).g && (p1).b == (p2).b)
|
||||||
#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); \
|
||||||
@ -139,12 +148,6 @@
|
|||||||
}
|
}
|
||||||
#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
|
||||||
@ -177,7 +180,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)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
size_t len = 3;
|
size_t len = 3;
|
||||||
#elif defined(LZ_RGB16)
|
#elif defined(LZ_RGB16)
|
||||||
size_t len = 2;
|
size_t len = 2;
|
||||||
@ -199,9 +202,7 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,7 +235,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)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16) || defined(LZ_A8)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -244,7 +245,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ip++;
|
ip++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -255,7 +256,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)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
if (ref >= (ref_limit - 1)) {
|
if (ref >= (ref_limit - 1)) {
|
||||||
goto literal;
|
goto literal;
|
||||||
}
|
}
|
||||||
@ -272,7 +273,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)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -310,7 +311,6 @@ 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
|
||||||
for (;;) {
|
|
||||||
while ((ip < ip_bound) && (ref < ref_limit)) {
|
while ((ip < ip_bound) && (ref < ref_limit)) {
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
@ -321,8 +321,6 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
|
|||||||
ip++;
|
ip++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we have copied something, adjust the copy count */
|
/* if we have copied something, adjust the copy count */
|
||||||
@ -393,27 +391,23 @@ 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;
|
||||||
ip++;
|
|
||||||
encoder->htab[hval].image_seg = seg;
|
encoder->htab[hval].image_seg = seg;
|
||||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
||||||
} else {ip++;
|
|
||||||
}
|
}
|
||||||
#endif
|
ip++;
|
||||||
#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;
|
||||||
ip++;
|
|
||||||
encoder->htab[hval].image_seg = seg;
|
encoder->htab[hval].image_seg = seg;
|
||||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
||||||
} else {ip++;
|
|
||||||
}
|
}
|
||||||
#endif
|
ip++;
|
||||||
/* assuming literal copy */
|
/* assuming literal copy */
|
||||||
encode_copy_count(encoder, MAX_COPY - 1);
|
encode_copy_count(encoder, MAX_COPY - 1);
|
||||||
continue;
|
continue;
|
||||||
@ -513,17 +507,11 @@ 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 BYTES_TO_16
|
#undef GET_rgb
|
||||||
#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 HASH_FUNC2
|
#undef LZ_A8
|
||||||
@ -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 __LZ_CONFIG_H
|
#ifndef H_SPICE_COMMON_LZ_CONFIG
|
||||||
#define __LZ_CONFIG_H
|
#define H_SPICE_COMMON_LZ_CONFIG
|
||||||
|
|
||||||
#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 //__LZ_CONFIG_H
|
#endif // H_SPICE_COMMON_LZ_CONFIG
|
||||||
@ -59,9 +59,7 @@
|
|||||||
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)
|
||||||
@ -153,6 +151,26 @@
|
|||||||
#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
|
||||||
@ -204,18 +222,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 *op_limit = out_buf + size;
|
OUT_PIXEL *const op_limit = out_buf + size;
|
||||||
uint32_t ctrl = decode(encoder);
|
|
||||||
int loop = TRUE;
|
|
||||||
|
|
||||||
do {
|
for (;;) {
|
||||||
const OUT_PIXEL *ref = op;
|
uint32_t ctrl = decode(encoder);
|
||||||
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;
|
||||||
@ -237,7 +255,7 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
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)
|
||||||
@ -246,17 +264,13 @@ 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;
|
||||||
|
|
||||||
ASSERT(encoder->usr, op + len <= op_limit);
|
spice_assert(op + len <= op_limit);
|
||||||
ASSERT(encoder->usr, ref + len <= op_limit);
|
spice_assert(ref + len <= op_limit);
|
||||||
ASSERT(encoder->usr, ref >= out_buf);
|
spice_assert(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
|
||||||
@ -267,41 +281,31 @@ 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 */
|
||||||
OUT_PIXEL b = *ref;
|
const OUT_PIXEL b = *ref;
|
||||||
for (; len; --len) {
|
for (; len; --len) {
|
||||||
COPY_PIXEL(b, op);
|
COPY_PIXEL(b, op);
|
||||||
ASSERT(encoder->usr, op <= op_limit);
|
spice_extra_assert(op <= op_limit);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (; len; --len) {
|
for (; len; --len) {
|
||||||
COPY_REF_PIXEL(ref, op);
|
COPY_REF_PIXEL(ref, op);
|
||||||
ASSERT(encoder->usr, op <= op_limit);
|
spice_extra_assert(op <= op_limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // copy
|
} else { // copy
|
||||||
ctrl++; // copy count is biased by 1
|
ctrl++; // copy count is biased by 1
|
||||||
#if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \
|
spice_assert(op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
|
||||||
defined(PLT1_LE))
|
|
||||||
ASSERT(encoder->usr, op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
|
do {
|
||||||
#else
|
|
||||||
ASSERT(encoder->usr, op + ctrl <= op_limit);
|
|
||||||
#endif
|
|
||||||
COPY_COMP_PIXEL(encoder, op);
|
COPY_COMP_PIXEL(encoder, op);
|
||||||
|
spice_extra_assert(op <= op_limit);
|
||||||
ASSERT(encoder->usr, op <= op_limit);
|
} while(--ctrl);
|
||||||
|
|
||||||
for (--ctrl; ctrl; ctrl--) {
|
|
||||||
COPY_COMP_PIXEL(encoder, op);
|
|
||||||
ASSERT(encoder->usr, op <= op_limit);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
|
if (LZ_UNEXPECT_CONDITIONAL(op >= op_limit)) {
|
||||||
ctrl = decode(encoder);
|
break;
|
||||||
} else {
|
}
|
||||||
loop = FALSE;
|
|
||||||
}
|
}
|
||||||
} while (LZ_EXPECT_CONDITIONAL(loop));
|
|
||||||
|
|
||||||
return (op - out_buf);
|
return (op - out_buf);
|
||||||
}
|
}
|
||||||
@ -315,6 +319,7 @@ 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
|
||||||
56
common/macros.h
Normal file
56
common/macros.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* -*- 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,34 +15,60 @@
|
|||||||
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_int8(ptr,v) (*((int8_t *)(ptr)) = v)
|
#define write_int16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||||
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
|
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||||
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
|
#define write_int32(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_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
|
||||||
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
|
#define write_int64(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_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_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_int8(ptr,v) (*((int8_t *)(ptr)) = v)
|
#define write_int16(ptr,v) (((int16_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
|
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = v)
|
#define write_int32(ptr,v) (((int32_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = v)
|
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = v)
|
#define write_int64(ptr,v) (((int64_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = v)
|
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = 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 {
|
||||||
@ -68,7 +94,6 @@ 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;
|
||||||
|
|
||||||
@ -80,25 +105,26 @@ struct SpiceMarshaller {
|
|||||||
MarshallerRef pointer_ref;
|
MarshallerRef pointer_ref;
|
||||||
|
|
||||||
int n_items;
|
int n_items;
|
||||||
int items_size; /* number of items availible in items */
|
int items_size; /* number of items available 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;
|
|
||||||
|
|
||||||
SpiceMarshaller static_marshaller;
|
// first marshaller and buffer are statically allocated here
|
||||||
MarshallerBuffer static_buffer;
|
SpiceMarshaller marshallers[1];
|
||||||
|
MarshallerBuffer buffers[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
static void spice_marshaller_init(SpiceMarshaller *m,
|
static void spice_marshaller_init(SpiceMarshaller *m,
|
||||||
@ -111,6 +137,8 @@ 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)
|
||||||
@ -120,16 +148,15 @@ SpiceMarshaller *spice_marshaller_new(void)
|
|||||||
|
|
||||||
d = spice_new(SpiceMarshallerData, 1);
|
d = spice_new(SpiceMarshallerData, 1);
|
||||||
|
|
||||||
d->last_marshaller = d->marshallers = &d->static_marshaller;
|
d->last_marshaller = d->marshallers;
|
||||||
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->static_marshaller;
|
m = d->marshallers;
|
||||||
spice_marshaller_init(m, d);
|
spice_marshaller_init(m, d);
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
@ -160,6 +187,7 @@ 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);
|
||||||
@ -179,6 +207,14 @@ 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;
|
||||||
@ -238,6 +274,11 @@ 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;
|
||||||
@ -276,7 +317,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 = (spice_marshaller_item_free_func)free;
|
item->free_data = reserve_space_free_data;
|
||||||
item->opaque = NULL;
|
item->opaque = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* Use next buffer */
|
/* Use next buffer */
|
||||||
@ -310,7 +351,7 @@ void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size)
|
|||||||
item->len -= size;
|
item->len -= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
uint8_t *spice_marshaller_add_by_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;
|
||||||
@ -333,7 +374,7 @@ uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
|
uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
|
|
||||||
@ -342,17 +383,20 @@ uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size)
|
uint8_t *spice_marshaller_add_by_ref(SpiceMarshaller *m, const uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
return spice_marshaller_add_ref_full(m, data, size, NULL, NULL);
|
/* the cast to no-const here is safe as data is used for writing only if
|
||||||
|
* free_data pointer is not NULL
|
||||||
|
*/
|
||||||
|
return spice_marshaller_add_by_ref_full(m, (uint8_t *) data, size, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks)
|
void spice_marshaller_add_chunks_by_ref(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_ref(m, chunks->chunk[i].data,
|
spice_marshaller_add_by_ref(m, chunks->chunk[i].data,
|
||||||
chunks->chunk[i].len);
|
chunks->chunk[i].len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,13 +417,13 @@ SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m)
|
|||||||
return m2;
|
return m2;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit)
|
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m)
|
||||||
{
|
{
|
||||||
SpiceMarshaller *m2;
|
SpiceMarshaller *m2;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
size = is_64bit ? 8 : 4;
|
size = 4;
|
||||||
|
|
||||||
p = spice_marshaller_reserve_space(m, size);
|
p = spice_marshaller_reserve_space(m, size);
|
||||||
memset(p, 0, size);
|
memset(p, 0, size);
|
||||||
@ -387,12 +431,11 @@ SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *lookup_ref(MarshallerRef *ref)
|
static uint8_t *lookup_ref(MarshallerRef *ref)
|
||||||
{
|
{
|
||||||
MarshallerItem *item;
|
MarshallerItem *item;
|
||||||
|
|
||||||
@ -419,7 +462,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) {
|
if (m->n_items == 1 && m->next == NULL) {
|
||||||
*free_res = FALSE;
|
*free_res = FALSE;
|
||||||
if (m->items[0].len <= skip_bytes) {
|
if (m->items[0].len <= skip_bytes) {
|
||||||
*len = 0;
|
*len = 0;
|
||||||
@ -492,18 +535,19 @@ 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);
|
||||||
if (m2->pointer_ref.is_64bit) {
|
write_uint32(ptr_pos, spice_marshaller_get_offset(m2));
|
||||||
write_uint64(ptr_pos,
|
|
||||||
spice_marshaller_get_offset(m2));
|
|
||||||
} else {
|
|
||||||
write_uint32(ptr_pos,
|
|
||||||
spice_marshaller_get_offset(m2));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifdef 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)
|
||||||
{
|
{
|
||||||
@ -525,7 +569,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 = (void *)item->data + skip_bytes;
|
vec[v].iov_base = (uint8_t *)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++;
|
||||||
@ -535,7 +579,6 @@ 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)
|
||||||
{
|
{
|
||||||
@ -564,7 +607,7 @@ void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
|
|||||||
return (void *)ptr;
|
return (void *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v)
|
void spice_marshaller_set_uint32(SPICE_GNUC_UNUSED SpiceMarshaller *m, void *ref, uint32_t v)
|
||||||
{
|
{
|
||||||
write_uint32((uint8_t *)ref, v);
|
write_uint32((uint8_t *)ref, v);
|
||||||
}
|
}
|
||||||
@ -613,3 +656,26 @@ 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,18 +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_MARSHALLER
|
#ifndef H_SPICE_COMMON_MARSHALLER
|
||||||
#define _H_MARSHALLER
|
#define H_SPICE_COMMON_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
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
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);
|
||||||
@ -37,11 +39,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, uint8_t *data, size_t size);
|
uint8_t *spice_marshaller_add(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(SpiceMarshaller *m, const uint8_t *data, size_t size);
|
||||||
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
uint8_t *spice_marshaller_add_by_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_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks);
|
void spice_marshaller_add_chunks_by_ref(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,
|
||||||
@ -51,11 +53,9 @@ 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, int is_64bit);
|
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m);
|
||||||
#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,8 +67,9 @@ 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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
void spice_marshaller_add_fd(SpiceMarshaller *m, int fd);
|
||||||
}
|
int spice_marshaller_get_fds(SpiceMarshaller *m, int fd[4]);
|
||||||
#endif
|
|
||||||
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -15,20 +15,17 @@
|
|||||||
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(format, ...) { \
|
#define MALLOC_ERROR(...) SPICE_STMT_START { \
|
||||||
printf(format "\n", ## __VA_ARGS__); \
|
spice_error(__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)
|
||||||
@ -46,13 +43,15 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy = (char *)spice_malloc(strlen(str) + 1);
|
len = strlen(str) + 1;
|
||||||
strcpy(copy, str);
|
copy = (char *)spice_malloc(len);
|
||||||
|
memcpy(copy, str, len);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +93,7 @@ void *spice_malloc(size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("spice_malloc: panic: unable to allocate %lu bytes\n",
|
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||||
(unsigned long)n_bytes);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -111,8 +109,7 @@ void *spice_malloc0(size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("spice_malloc0: panic: unable to allocate %lu bytes\n",
|
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||||
(unsigned long)n_bytes);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -126,8 +123,7 @@ void *spice_realloc(void *mem, size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("spice_realloc: panic: unable to allocate %lu bytes\n",
|
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||||
(unsigned long)n_bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(mem);
|
free(mem);
|
||||||
@ -140,7 +136,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("spice_malloc_n: overflow allocating %lu*%lu bytes",
|
MALLOC_ERROR("overflow allocating %lu*%lu bytes",
|
||||||
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,3 +291,25 @@ 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
|
||||||
@ -16,19 +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_MEM
|
#ifndef H_SPICE_COMMON_MEM
|
||||||
#define _H_MEM
|
#define H_SPICE_COMMON_MEM
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
SPICE_BEGIN_DECLS
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef STDC_HEADERS
|
#ifdef STDC_HEADERS
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@ -134,7 +129,6 @@ 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) \
|
||||||
@ -142,6 +136,46 @@ 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)
|
||||||
@ -156,7 +190,6 @@ 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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
194
common/meson.build
Normal file
194
common/meson.build
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#
|
||||||
|
# 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
|
||||||
73
common/messages.h
Normal file
73
common/messages.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2009-2010 Red Hat, Inc.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
|
||||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_SPICE_COMMON_MESSAGES
|
||||||
|
#define H_SPICE_COMMON_MESSAGES
|
||||||
|
|
||||||
|
#include <spice/protocol.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
#ifdef USE_SMARTCARD
|
||||||
|
#include <libcacard.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "draw.h"
|
||||||
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct SpiceMsgCompressedData {
|
||||||
|
uint8_t type;
|
||||||
|
uint32_t uncompressed_size;
|
||||||
|
uint32_t compressed_size;
|
||||||
|
uint8_t *compressed_data;
|
||||||
|
} SpiceMsgCompressedData;
|
||||||
|
|
||||||
|
#define SPICE_AGENT_MAX_DATA_SIZE 2048
|
||||||
|
|
||||||
|
#ifdef USE_SMARTCARD
|
||||||
|
typedef struct SpiceMsgSmartcard {
|
||||||
|
VSCMsgType type;
|
||||||
|
uint32_t length;
|
||||||
|
uint32_t reader_id;
|
||||||
|
uint8_t data[0];
|
||||||
|
} SpiceMsgSmartcard;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <common/generated_messages.h>
|
||||||
|
|
||||||
|
typedef SpiceMsgMainAgentTokens SpiceMsgcMainAgentTokens;
|
||||||
|
typedef SpiceMsgMainAgentTokens SpiceMsgcMainAgentStart;
|
||||||
|
typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
|
||||||
|
typedef SpiceMsgPlaybackMode SpiceMsgcRecordMode;
|
||||||
|
typedef SpiceMsgPlaybackPacket SpiceMsgcRecordPacket;
|
||||||
|
|
||||||
|
SPICE_END_DECLS
|
||||||
|
|
||||||
|
#endif // H_SPICE_COMMON_MESSAGES
|
||||||
@ -15,22 +15,26 @@
|
|||||||
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, _type src) \
|
solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, SPICE_GNUC_UNUSED _type src) \
|
||||||
{ \
|
{ \
|
||||||
while (len--) { \
|
while (len--) { \
|
||||||
_type dst = *ptr; \
|
_type dst = *ptr; \
|
||||||
@ -206,12 +210,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 */
|
||||||
|
|
||||||
ASSERT(x >= 0);
|
spice_assert(x >= 0);
|
||||||
ASSERT(y >= 0);
|
spice_assert(y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||||
|
|
||||||
if (pixman_fill(bits,
|
if (pixman_fill(bits,
|
||||||
stride / 4,
|
stride / 4,
|
||||||
@ -231,7 +235,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 {
|
||||||
ASSERT (depth == 32)
|
spice_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;
|
||||||
}
|
}
|
||||||
@ -298,13 +302,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 */
|
||||||
|
|
||||||
ASSERT(x >= 0);
|
spice_assert(x >= 0);
|
||||||
ASSERT(y >= 0);
|
spice_assert(y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(rop >= 0 && rop < 16);
|
spice_assert(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];
|
||||||
@ -358,13 +362,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);
|
||||||
|
|
||||||
ASSERT(x >= 0);
|
spice_assert(x >= 0);
|
||||||
ASSERT(y >= 0);
|
spice_assert(y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(depth == spice_pixman_image_get_bpp(tile));
|
spice_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) {
|
||||||
@ -406,7 +410,7 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ASSERT (depth == 32);
|
spice_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;
|
||||||
@ -449,14 +453,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);
|
||||||
|
|
||||||
ASSERT(x >= 0);
|
spice_assert(x >= 0);
|
||||||
ASSERT(y >= 0);
|
spice_assert(y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(rop >= 0 && rop < 16);
|
spice_assert(rop < 16);
|
||||||
ASSERT(depth == spice_pixman_image_get_bpp(tile));
|
spice_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) {
|
||||||
@ -504,7 +508,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];
|
||||||
|
|
||||||
ASSERT (depth == 32);
|
spice_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;
|
||||||
@ -536,6 +540,11 @@ 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);
|
||||||
@ -569,17 +578,17 @@ void spice_pixman_blit(pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(src_x >= 0);
|
spice_assert(src_x >= 0);
|
||||||
ASSERT(src_y >= 0);
|
spice_assert(src_y >= 0);
|
||||||
ASSERT(dest_x >= 0);
|
spice_assert(dest_x >= 0);
|
||||||
ASSERT(dest_y >= 0);
|
spice_assert(dest_y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||||
ASSERT(depth == src_depth);
|
spice_assert(depth == src_depth);
|
||||||
|
|
||||||
if (pixman_blt(src_bits,
|
if (pixman_blt(src_bits,
|
||||||
bits,
|
bits,
|
||||||
@ -601,7 +610,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 {
|
||||||
ASSERT (depth == 32);
|
spice_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;
|
||||||
@ -660,17 +669,17 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(src_x >= 0);
|
spice_assert(src_x >= 0);
|
||||||
ASSERT(src_y >= 0);
|
spice_assert(src_y >= 0);
|
||||||
ASSERT(dest_x >= 0);
|
spice_assert(dest_x >= 0);
|
||||||
ASSERT(dest_y >= 0);
|
spice_assert(dest_y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||||
ASSERT(depth == src_depth);
|
spice_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];
|
||||||
@ -697,7 +706,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];
|
||||||
|
|
||||||
ASSERT (depth == 32);
|
spice_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;
|
||||||
|
|
||||||
@ -756,17 +765,17 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(src_x >= 0);
|
spice_assert(src_x >= 0);
|
||||||
ASSERT(src_y >= 0);
|
spice_assert(src_y >= 0);
|
||||||
ASSERT(dest_x >= 0);
|
spice_assert(dest_x >= 0);
|
||||||
ASSERT(dest_y >= 0);
|
spice_assert(dest_y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||||
ASSERT(depth == spice_pixman_image_get_bpp(src));
|
spice_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;
|
||||||
@ -806,7 +815,7 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
|
|||||||
src_line += src_stride;
|
src_line += src_stride;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ASSERT (depth == 32);
|
spice_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;
|
||||||
|
|
||||||
@ -924,8 +933,7 @@ 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:
|
||||||
printf("Unknown surface format %d\n", surface_format);
|
g_error("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 */
|
||||||
@ -958,10 +966,12 @@ 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:
|
||||||
printf("Unknown bitmap format %d\n", bitmap_format);
|
g_error("Unknown bitmap format %d\n", bitmap_format);
|
||||||
abort();
|
|
||||||
return PIXMAN_a8r8g8b8;
|
return PIXMAN_a8r8g8b8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -985,25 +995,13 @@ 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:
|
||||||
#ifdef WORDS_BIGENDIAN
|
pixman_format = PIXMAN_LE_x8r8g8b8;
|
||||||
pixman_format = PIXMAN_b8g8r8x8;
|
|
||||||
#else
|
|
||||||
pixman_format = PIXMAN_x8r8g8b8;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_RGBA:
|
case SPICE_BITMAP_FMT_RGBA:
|
||||||
#ifdef WORDS_BIGENDIAN
|
pixman_format = PIXMAN_LE_a8r8g8b8;
|
||||||
pixman_format = PIXMAN_b8g8r8a8;
|
|
||||||
#else
|
|
||||||
pixman_format = PIXMAN_a8r8g8b8;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_24BIT:
|
case SPICE_BITMAP_FMT_24BIT:
|
||||||
#ifdef WORDS_BIGENDIAN
|
pixman_format = PIXMAN_LE_r8g8b8;
|
||||||
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
|
||||||
@ -1037,26 +1035,6 @@ 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)
|
||||||
@ -1078,6 +1056,15 @@ 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)
|
||||||
@ -1131,7 +1118,7 @@ static void bitmap_8_32_to_32(uint8_t *dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
PANIC("No palette");
|
spice_error("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1177,7 +1164,7 @@ static void bitmap_8_16_to_16_555(uint8_t *dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
PANIC("No palette");
|
spice_error("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1223,7 +1210,7 @@ static void bitmap_4be_32_to_32(uint8_t* dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
PANIC("No palette");
|
spice_error("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1273,7 +1260,7 @@ static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
PANIC("No palette");
|
spice_error("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1310,7 +1297,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)));
|
||||||
}
|
}
|
||||||
@ -1323,7 +1310,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;
|
||||||
|
|
||||||
ASSERT(palette != NULL);
|
spice_assert(palette != NULL);
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
return;
|
return;
|
||||||
@ -1355,7 +1342,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;
|
||||||
|
|
||||||
ASSERT(palette != NULL);
|
spice_assert(palette != NULL);
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
return;
|
return;
|
||||||
@ -1380,6 +1367,25 @@ 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)
|
||||||
@ -1461,7 +1467,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)) {
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
dest += dest_stride * (height - 1);
|
dest += dest_stride * (height - 1);
|
||||||
dest_stride = -dest_stride;
|
dest_stride = -dest_stride;
|
||||||
}
|
}
|
||||||
@ -1472,6 +1478,9 @@ 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;
|
||||||
@ -1485,7 +1494,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 {
|
||||||
PANIC("Unsupported palette format");
|
spice_error("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_4BIT_BE:
|
case SPICE_BITMAP_FMT_4BIT_BE:
|
||||||
@ -1495,7 +1504,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 {
|
||||||
PANIC("Unsupported palette format");
|
spice_error("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_1BIT_BE:
|
case SPICE_BITMAP_FMT_1BIT_BE:
|
||||||
@ -1505,11 +1514,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 {
|
||||||
PANIC("Unsupported palette format");
|
spice_error("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PANIC("Unsupported bitmap format");
|
spice_error("Unsupported bitmap format");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,20 +16,29 @@
|
|||||||
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__PIXMAN_UTILS
|
#ifndef H_SPICE_COMMON_PIXMAN_UTILS
|
||||||
#define _H__PIXMAN_UTILS
|
#define H_SPICE_COMMON_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 __cplusplus
|
#ifdef WORDS_BIGENDIAN
|
||||||
extern "C" {
|
# define PIXMAN_LE_x8r8g8b8 PIXMAN_b8g8r8x8
|
||||||
|
# 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
|
||||||
@ -129,8 +138,6 @@ 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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _H__PIXMAN_UTILS */
|
#endif // H_SPICE_COMMON_PIXMAN_UTILS
|
||||||
File diff suppressed because it is too large
Load Diff
@ -16,14 +16,13 @@
|
|||||||
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 __QUIC_H
|
#ifndef H_SPICE_COMMON_QUIC
|
||||||
#define __QUIC_H
|
#define H_SPICE_COMMON_QUIC
|
||||||
|
|
||||||
#include "quic_config.h"
|
#include <spice/macros.h>
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QUIC_IMAGE_TYPE_INVALID,
|
QUIC_IMAGE_TYPE_INVALID,
|
||||||
@ -41,9 +40,10 @@ typedef void *QuicContext;
|
|||||||
|
|
||||||
typedef struct QuicUsrContext QuicUsrContext;
|
typedef struct QuicUsrContext QuicUsrContext;
|
||||||
struct QuicUsrContext {
|
struct QuicUsrContext {
|
||||||
void (*error)(QuicUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_NORETURN
|
||||||
void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_PRINTF(2, 3) void (*error)(QuicUsrContext *usr, const char *fmt, ...);
|
||||||
void (*info)(QuicUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_PRINTF(2, 3) void (*warn)(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,10 +63,6 @@ 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);
|
||||||
|
|
||||||
void quic_init(void);
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -16,15 +16,13 @@
|
|||||||
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 __QUIC_CONFIG_H
|
#ifndef H_SPICE_COMMON_QUIC_CONFIG
|
||||||
#define __QUIC_CONFIG_H
|
#define H_SPICE_COMMON_QUIC_CONFIG
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -41,8 +39,6 @@ extern "C" {
|
|||||||
#endif // QXLDD
|
#endif // QXLDD
|
||||||
#endif //__GNUC__
|
#endif //__GNUC__
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -15,9 +15,7 @@
|
|||||||
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
|
||||||
@ -34,26 +32,19 @@
|
|||||||
#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)
|
|
||||||
{
|
{
|
||||||
if (n < VNAME(family).nGRcodewords[l]) {
|
return VNAME(family).golomb_code[n][l];
|
||||||
return (n >> l) + 1 + l;
|
|
||||||
} else {
|
|
||||||
return VNAME(family).notGRcwlen[l];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FNAME(golomb_coding)(const BYTE n, const unsigned int l, unsigned int * const codeword,
|
static inline unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
|
||||||
unsigned int * const codewordlen)
|
|
||||||
{
|
{
|
||||||
if (n < VNAME(family).nGRcodewords[l]) {
|
return VNAME(family).golomb_code_len[n][l];
|
||||||
(*codeword) = bitat[l] | (n & bppmask[l]);
|
|
||||||
(*codewordlen) = (n >> l) + l + 1;
|
|
||||||
} else {
|
|
||||||
(*codeword) = n - VNAME(family).nGRcodewords[l];
|
|
||||||
(*codewordlen) = VNAME(family).notGRcwlen[l];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FNAME(golomb_coding)(Encoder *encoder, const BYTE n, const unsigned int l)
|
||||||
|
{
|
||||||
|
encode(encoder, FNAME(golomb_code)(n, l), FNAME(golomb_code_len)(n, 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,
|
||||||
@ -74,13 +65,16 @@ 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, unsigned int bpp)
|
const BYTE curval)
|
||||||
{
|
{
|
||||||
|
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 */
|
||||||
|
|
||||||
@ -107,9 +101,14 @@ 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)
|
||||||
{
|
{
|
||||||
ASSERT(channel->encoder->usr, val < (0x1U << BPC));
|
spice_extra_assert(val < (0x1U << BPC));
|
||||||
|
|
||||||
return channel->_buckets_ptrs[val];
|
/* The and (&) here is to avoid buffer overflows in case of garbage or malicious
|
||||||
|
* 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
|
||||||
662
common/quic_tmpl.c
Normal file
662
common/quic_tmpl.c
Normal file
@ -0,0 +1,662 @@
|
|||||||
|
/* -*- 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 <config.h>
|
||||||
|
|
||||||
|
#define COMPRESS_IMP
|
||||||
|
|
||||||
|
#if defined(ONE_BYTE) || defined(FOUR_BYTE)
|
||||||
|
# define FARGS_DECL(...) (Encoder *encoder, Channel *channel_a, __VA_ARGS__)
|
||||||
|
# define FARGS_CALL(...) (encoder, channel_a, __VA_ARGS__)
|
||||||
|
# define UNCOMPRESS_PIX_START(row) do { } while (0)
|
||||||
|
# define SET_a(pix, val) ((pix)->a = val)
|
||||||
|
# define GET_a(pix) ((pix)->a)
|
||||||
|
# define SAME_PIXEL(p1, p2) (GET_a(p1) == GET_a(p2))
|
||||||
|
# define COPY_PIXEL(dest, src) \
|
||||||
|
SET_a(dest, GET_a(src));
|
||||||
|
# define DECLARE_STATE_VARIABLES \
|
||||||
|
CommonState *state = &channel_a->state
|
||||||
|
# define DECLARE_CHANNEL_VARIABLES \
|
||||||
|
BYTE * const correlate_row_a = channel_a->correlate_row
|
||||||
|
# define APPLY_ALL_COMP(macro, ...) \
|
||||||
|
macro(a, ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define FARGS_DECL(...) (Encoder *encoder, __VA_ARGS__)
|
||||||
|
# define FARGS_CALL(...) (encoder, __VA_ARGS__)
|
||||||
|
# define SAME_PIXEL(p1, p2) \
|
||||||
|
(GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
|
||||||
|
GET_b(p1) == GET_b(p2))
|
||||||
|
# define COPY_PIXEL(dest, src) \
|
||||||
|
SET_r(dest, GET_r(src)); \
|
||||||
|
SET_g(dest, GET_g(src)); \
|
||||||
|
SET_b(dest, GET_b(src))
|
||||||
|
# define DECLARE_STATE_VARIABLES \
|
||||||
|
CommonState *state = &encoder->rgb_state
|
||||||
|
# define DECLARE_CHANNEL_VARIABLES \
|
||||||
|
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
|
||||||
|
# define APPLY_ALL_COMP(macro, ...) \
|
||||||
|
macro(r, ## __VA_ARGS__); \
|
||||||
|
macro(g, ## __VA_ARGS__); \
|
||||||
|
macro(b, ## __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ONE_BYTE
|
||||||
|
#undef ONE_BYTE
|
||||||
|
#define FNAME(name) quic_one_##name
|
||||||
|
#define PIXEL one_byte_t
|
||||||
|
#define BPC 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FOUR_BYTE
|
||||||
|
#undef FOUR_BYTE
|
||||||
|
#define FNAME(name) quic_four_##name
|
||||||
|
#define PIXEL four_bytes_t
|
||||||
|
#define BPC 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QUIC_RGB32
|
||||||
|
#undef QUIC_RGB32
|
||||||
|
#define PIXEL rgb32_pixel_t
|
||||||
|
#define FNAME(name) quic_rgb32_##name
|
||||||
|
#define BPC 8
|
||||||
|
#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 BPC 8
|
||||||
|
#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 BPC 5
|
||||||
|
#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 BPC 5
|
||||||
|
#undef COMPRESS_IMP
|
||||||
|
#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 FNAME_DECL(name) FNAME(name) FARGS_DECL
|
||||||
|
#define FNAME_CALL(name) FNAME(name) FARGS_CALL
|
||||||
|
|
||||||
|
#if BPC == 5
|
||||||
|
# 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_MASK 0x1fU
|
||||||
|
#elif BPC == 8
|
||||||
|
# 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_MASK 0xffU
|
||||||
|
#else
|
||||||
|
# error BPC must be 5 or 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _PIXEL_A(channel, curr) ((unsigned int)GET_##channel((curr) - 1))
|
||||||
|
#define _PIXEL_B(channel, prev) ((unsigned int)GET_##channel(prev))
|
||||||
|
|
||||||
|
/* a */
|
||||||
|
|
||||||
|
#define DECORRELATE_0(channel, curr, bpc_mask)\
|
||||||
|
family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)_PIXEL_A(channel, curr)) & bpc_mask]
|
||||||
|
|
||||||
|
#define CORRELATE_0(channel, curr, correlate, bpc_mask)\
|
||||||
|
((family.xlatL2U[correlate] + _PIXEL_A(channel, curr)) & bpc_mask)
|
||||||
|
|
||||||
|
|
||||||
|
/* (a+b)/2 */
|
||||||
|
#define DECORRELATE(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 CORRELATE(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))
|
||||||
|
|
||||||
|
|
||||||
|
#define COMPRESS_ONE_ROW0_0(channel) \
|
||||||
|
correlate_row_##channel[0] = family.xlatU2L[GET_##channel(cur_row)];\
|
||||||
|
golomb_coding(encoder, correlate_row_##channel[0], \
|
||||||
|
find_bucket(channel_##channel, \
|
||||||
|
correlate_row_##channel[-1])->bestcode)
|
||||||
|
|
||||||
|
#define COMPRESS_ONE_ROW0(channel, index) \
|
||||||
|
correlate_row_##channel[index] = DECORRELATE_0(channel, &cur_row[index], bpc_mask); \
|
||||||
|
golomb_coding(encoder, correlate_row_##channel[index], \
|
||||||
|
find_bucket(channel_##channel, \
|
||||||
|
correlate_row_##channel[index - 1])->bestcode)
|
||||||
|
|
||||||
|
#define UPDATE_MODEL_COMP(channel, index) \
|
||||||
|
update_model(state, find_bucket(channel_##channel, correlate_row_##channel[index - 1]), \
|
||||||
|
correlate_row_##channel[index])
|
||||||
|
#define UPDATE_MODEL(index) APPLY_ALL_COMP(UPDATE_MODEL_COMP, index)
|
||||||
|
|
||||||
|
#define RLE_PRED_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; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef COMPRESS_IMP
|
||||||
|
|
||||||
|
static void FNAME_DECL(compress_row0_seg)(int i,
|
||||||
|
const PIXEL * const cur_row,
|
||||||
|
const int end,
|
||||||
|
const unsigned int waitmask,
|
||||||
|
const unsigned int bpc_mask)
|
||||||
|
{
|
||||||
|
DECLARE_STATE_VARIABLES;
|
||||||
|
DECLARE_CHANNEL_VARIABLES;
|
||||||
|
int stopidx;
|
||||||
|
|
||||||
|
spice_assert(end - i > 0);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
APPLY_ALL_COMP(COMPRESS_ONE_ROW0_0);
|
||||||
|
|
||||||
|
if (state->waitcnt) {
|
||||||
|
state->waitcnt--;
|
||||||
|
} else {
|
||||||
|
state->waitcnt = (tabrand(&state->tabrand_seed) & waitmask);
|
||||||
|
UPDATE_MODEL(0);
|
||||||
|
}
|
||||||
|
stopidx = ++i + state->waitcnt;
|
||||||
|
} else {
|
||||||
|
stopidx = i + state->waitcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (stopidx < end) {
|
||||||
|
for (; i <= stopidx; i++) {
|
||||||
|
APPLY_ALL_COMP(COMPRESS_ONE_ROW0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
UPDATE_MODEL(stopidx);
|
||||||
|
stopidx = i + (tabrand(&state->tabrand_seed) & waitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < end; i++) {
|
||||||
|
APPLY_ALL_COMP(COMPRESS_ONE_ROW0, i);
|
||||||
|
}
|
||||||
|
state->waitcnt = stopidx - end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef COMPRESS_ONE_ROW0_0
|
||||||
|
#undef COMPRESS_ONE_ROW0
|
||||||
|
|
||||||
|
static void FNAME_DECL(compress_row0)(const PIXEL *cur_row, unsigned int width)
|
||||||
|
{
|
||||||
|
DECLARE_STATE_VARIABLES;
|
||||||
|
const unsigned int bpc_mask = BPC_MASK;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while ((DEFwmimax > (int)state->wmidx) && (state->wmileft <= width)) {
|
||||||
|
if (state->wmileft) {
|
||||||
|
FNAME_CALL(compress_row0_seg)(pos, cur_row, pos + state->wmileft,
|
||||||
|
bppmask[state->wmidx], bpc_mask);
|
||||||
|
width -= state->wmileft;
|
||||||
|
pos += state->wmileft;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->wmidx++;
|
||||||
|
set_wm_trigger(state);
|
||||||
|
state->wmileft = DEFwminext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) {
|
||||||
|
FNAME_CALL(compress_row0_seg)(pos, cur_row, pos + width,
|
||||||
|
bppmask[state->wmidx], bpc_mask);
|
||||||
|
if (DEFwmimax > (int)state->wmidx) {
|
||||||
|
state->wmileft -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spice_assert((int)state->wmidx <= DEFwmimax);
|
||||||
|
spice_assert(state->wmidx <= 32);
|
||||||
|
spice_assert(DEFwminext > 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(encoder, correlate_row_##channel[0], \
|
||||||
|
find_bucket(channel_##channel, correlate_row_##channel[-1])->bestcode)
|
||||||
|
|
||||||
|
#define COMPRESS_ONE(channel, index) \
|
||||||
|
DECORRELATE(channel, &prev_row[index], &cur_row[index],bpc_mask, correlate_row_##channel[index]); \
|
||||||
|
golomb_coding(encoder, correlate_row_##channel[index], \
|
||||||
|
find_bucket(channel_##channel, correlate_row_##channel[index - 1])->bestcode)
|
||||||
|
|
||||||
|
static void FNAME_DECL(compress_row_seg)(int i,
|
||||||
|
const PIXEL * const prev_row,
|
||||||
|
const PIXEL * const cur_row,
|
||||||
|
const int end,
|
||||||
|
const unsigned int waitmask,
|
||||||
|
const unsigned int bpc_mask)
|
||||||
|
{
|
||||||
|
DECLARE_STATE_VARIABLES;
|
||||||
|
DECLARE_CHANNEL_VARIABLES;
|
||||||
|
int stopidx;
|
||||||
|
int run_index = 0;
|
||||||
|
int run_size;
|
||||||
|
|
||||||
|
spice_assert(end - i > 0);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
APPLY_ALL_COMP(COMPRESS_ONE_0);
|
||||||
|
|
||||||
|
if (state->waitcnt) {
|
||||||
|
state->waitcnt--;
|
||||||
|
} else {
|
||||||
|
state->waitcnt = (tabrand(&state->tabrand_seed) & waitmask);
|
||||||
|
UPDATE_MODEL(0);
|
||||||
|
}
|
||||||
|
stopidx = ++i + state->waitcnt;
|
||||||
|
} else {
|
||||||
|
stopidx = i + state->waitcnt;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
while (stopidx < end) {
|
||||||
|
for (; i <= stopidx; i++) {
|
||||||
|
RLE_PRED_IMP;
|
||||||
|
APPLY_ALL_COMP(COMPRESS_ONE, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
UPDATE_MODEL(stopidx);
|
||||||
|
stopidx = i + (tabrand(&state->tabrand_seed) & waitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < end; i++) {
|
||||||
|
RLE_PRED_IMP;
|
||||||
|
APPLY_ALL_COMP(COMPRESS_ONE, i);
|
||||||
|
}
|
||||||
|
state->waitcnt = stopidx - end;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
do_run:
|
||||||
|
run_index = i;
|
||||||
|
state->waitcnt = stopidx - i;
|
||||||
|
run_size = 0;
|
||||||
|
|
||||||
|
while (SAME_PIXEL(&cur_row[i], &cur_row[i - 1])) {
|
||||||
|
run_size++;
|
||||||
|
if (++i == end) {
|
||||||
|
encode_state_run(encoder, state, run_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
encode_state_run(encoder, state, run_size);
|
||||||
|
stopidx = i + state->waitcnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FNAME_DECL(compress_row)(const PIXEL * const prev_row,
|
||||||
|
const PIXEL * const cur_row,
|
||||||
|
unsigned int width)
|
||||||
|
|
||||||
|
{
|
||||||
|
DECLARE_STATE_VARIABLES;
|
||||||
|
const unsigned int bpc_mask = BPC_MASK;
|
||||||
|
unsigned int pos = 0;
|
||||||
|
|
||||||
|
while ((DEFwmimax > (int)state->wmidx) && (state->wmileft <= width)) {
|
||||||
|
if (state->wmileft) {
|
||||||
|
FNAME_CALL(compress_row_seg)(pos, prev_row, cur_row,
|
||||||
|
pos + state->wmileft, bppmask[state->wmidx],
|
||||||
|
bpc_mask);
|
||||||
|
width -= state->wmileft;
|
||||||
|
pos += state->wmileft;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->wmidx++;
|
||||||
|
set_wm_trigger(state);
|
||||||
|
state->wmileft = DEFwminext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) {
|
||||||
|
FNAME_CALL(compress_row_seg)(pos, prev_row, cur_row, pos + width,
|
||||||
|
bppmask[state->wmidx], bpc_mask);
|
||||||
|
if (DEFwmimax > (int)state->wmidx) {
|
||||||
|
state->wmileft -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spice_assert((int)state->wmidx <= DEFwmimax);
|
||||||
|
spice_assert(state->wmidx <= 32);
|
||||||
|
spice_assert(DEFwminext > 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], CORRELATE_0(channel, &cur_row[i], correlate_row_##channel[i], \
|
||||||
|
bpc_mask)); \
|
||||||
|
decode_eatbits(encoder, codewordlen);
|
||||||
|
|
||||||
|
static void FNAME_DECL(uncompress_row0_seg)(int i,
|
||||||
|
PIXEL * const cur_row,
|
||||||
|
const int end,
|
||||||
|
const unsigned int waitmask,
|
||||||
|
const unsigned int bpc_mask)
|
||||||
|
{
|
||||||
|
DECLARE_STATE_VARIABLES;
|
||||||
|
DECLARE_CHANNEL_VARIABLES;
|
||||||
|
int stopidx;
|
||||||
|
|
||||||
|
spice_assert(end - i > 0);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
APPLY_ALL_COMP(UNCOMPRESS_ONE_ROW0_0);
|
||||||
|
|
||||||
|
if (state->waitcnt) {
|
||||||
|
--state->waitcnt;
|
||||||
|
} else {
|
||||||
|
state->waitcnt = (tabrand(&state->tabrand_seed) & waitmask);
|
||||||
|
UPDATE_MODEL(0);
|
||||||
|
}
|
||||||
|
stopidx = ++i + state->waitcnt;
|
||||||
|
} else {
|
||||||
|
stopidx = i + state->waitcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (stopidx < end) {
|
||||||
|
for (; i <= stopidx; i++) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
APPLY_ALL_COMP(UNCOMPRESS_ONE_ROW0);
|
||||||
|
}
|
||||||
|
UPDATE_MODEL(stopidx);
|
||||||
|
stopidx = i + (tabrand(&state->tabrand_seed) & waitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < end; i++) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
APPLY_ALL_COMP(UNCOMPRESS_ONE_ROW0);
|
||||||
|
}
|
||||||
|
state->waitcnt = stopidx - end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FNAME_DECL(uncompress_row0)(PIXEL * const cur_row,
|
||||||
|
unsigned int width)
|
||||||
|
|
||||||
|
{
|
||||||
|
DECLARE_STATE_VARIABLES;
|
||||||
|
const unsigned int bpc_mask = BPC_MASK;
|
||||||
|
unsigned int pos = 0;
|
||||||
|
|
||||||
|
while ((DEFwmimax > (int)state->wmidx) && (state->wmileft <= width)) {
|
||||||
|
if (state->wmileft) {
|
||||||
|
FNAME_CALL(uncompress_row0_seg)(pos, cur_row,
|
||||||
|
pos + state->wmileft,
|
||||||
|
bppmask[state->wmidx],
|
||||||
|
bpc_mask);
|
||||||
|
pos += state->wmileft;
|
||||||
|
width -= state->wmileft;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->wmidx++;
|
||||||
|
set_wm_trigger(state);
|
||||||
|
state->wmileft = DEFwminext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) {
|
||||||
|
FNAME_CALL(uncompress_row0_seg)(pos, cur_row, pos + width,
|
||||||
|
bppmask[state->wmidx], bpc_mask);
|
||||||
|
if (DEFwmimax > (int)state->wmidx) {
|
||||||
|
state->wmileft -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spice_assert((int)state->wmidx <= DEFwmimax);
|
||||||
|
spice_assert(state->wmidx <= 32);
|
||||||
|
spice_assert(DEFwminext > 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); \
|
||||||
|
CORRELATE(channel, &prev_row[i], &cur_row[i], correlate_row_##channel[i], bpc_mask, \
|
||||||
|
&cur_row[i]); \
|
||||||
|
decode_eatbits(encoder, codewordlen);
|
||||||
|
|
||||||
|
static void FNAME_DECL(uncompress_row_seg)(const PIXEL * const prev_row,
|
||||||
|
PIXEL * const cur_row,
|
||||||
|
int i,
|
||||||
|
const int end,
|
||||||
|
const unsigned int bpc_mask)
|
||||||
|
{
|
||||||
|
DECLARE_STATE_VARIABLES;
|
||||||
|
DECLARE_CHANNEL_VARIABLES;
|
||||||
|
const unsigned int waitmask = bppmask[state->wmidx];
|
||||||
|
int stopidx;
|
||||||
|
int run_index = 0;
|
||||||
|
int run_end;
|
||||||
|
|
||||||
|
spice_assert(end - i > 0);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
APPLY_ALL_COMP(UNCOMPRESS_ONE_0);
|
||||||
|
|
||||||
|
if (state->waitcnt) {
|
||||||
|
--state->waitcnt;
|
||||||
|
} else {
|
||||||
|
state->waitcnt = (tabrand(&state->tabrand_seed) & waitmask);
|
||||||
|
UPDATE_MODEL(0);
|
||||||
|
}
|
||||||
|
stopidx = ++i + state->waitcnt;
|
||||||
|
} else {
|
||||||
|
stopidx = i + state->waitcnt;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
while (stopidx < end) {
|
||||||
|
for (; i <= stopidx; i++) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
RLE_PRED_IMP;
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
APPLY_ALL_COMP(UNCOMPRESS_ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
UPDATE_MODEL(stopidx);
|
||||||
|
|
||||||
|
stopidx = i + (tabrand(&state->tabrand_seed) & waitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < end; i++) {
|
||||||
|
unsigned int codewordlen;
|
||||||
|
RLE_PRED_IMP;
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
APPLY_ALL_COMP(UNCOMPRESS_ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->waitcnt = stopidx - end;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
do_run:
|
||||||
|
state->waitcnt = stopidx - i;
|
||||||
|
run_index = i;
|
||||||
|
run_end = decode_state_run(encoder, state);
|
||||||
|
if (run_end < 0 || run_end > (end - i)) {
|
||||||
|
encoder->usr->error(encoder->usr, "wrong RLE\n");
|
||||||
|
}
|
||||||
|
run_end += i;
|
||||||
|
|
||||||
|
for (; i < run_end; i++) {
|
||||||
|
UNCOMPRESS_PIX_START(&cur_row[i]);
|
||||||
|
COPY_PIXEL(&cur_row[i], &cur_row[i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopidx = i + state->waitcnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FNAME_DECL(uncompress_row)(const PIXEL * const prev_row,
|
||||||
|
PIXEL * const cur_row,
|
||||||
|
unsigned int width)
|
||||||
|
|
||||||
|
{
|
||||||
|
DECLARE_STATE_VARIABLES;
|
||||||
|
const unsigned int bpc_mask = BPC_MASK;
|
||||||
|
unsigned int pos = 0;
|
||||||
|
|
||||||
|
while ((DEFwmimax > (int)state->wmidx) && (state->wmileft <= width)) {
|
||||||
|
if (state->wmileft) {
|
||||||
|
FNAME_CALL(uncompress_row_seg)(prev_row, cur_row, pos,
|
||||||
|
pos + state->wmileft, bpc_mask);
|
||||||
|
pos += state->wmileft;
|
||||||
|
width -= state->wmileft;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->wmidx++;
|
||||||
|
set_wm_trigger(state);
|
||||||
|
state->wmileft = DEFwminext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) {
|
||||||
|
FNAME_CALL(uncompress_row_seg)(prev_row, cur_row, pos,
|
||||||
|
pos + width, bpc_mask);
|
||||||
|
if (DEFwmimax > (int)state->wmidx) {
|
||||||
|
state->wmileft -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spice_assert((int)state->wmidx <= DEFwmimax);
|
||||||
|
spice_assert(state->wmidx <= 32);
|
||||||
|
spice_assert(DEFwminext > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef PIXEL
|
||||||
|
#undef FARGS_CALL
|
||||||
|
#undef FARGS_DECL
|
||||||
|
#undef FNAME
|
||||||
|
#undef FNAME_CALL
|
||||||
|
#undef FNAME_DECL
|
||||||
|
#undef _PIXEL_A
|
||||||
|
#undef _PIXEL_B
|
||||||
|
#undef SAME_PIXEL
|
||||||
|
#undef RLE_PRED_IMP
|
||||||
|
#undef UPDATE_MODEL
|
||||||
|
#undef DECORRELATE_0
|
||||||
|
#undef DECORRELATE
|
||||||
|
#undef COMPRESS_ONE_0
|
||||||
|
#undef COMPRESS_ONE
|
||||||
|
#undef CORRELATE_0
|
||||||
|
#undef CORRELATE
|
||||||
|
#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 SET_a
|
||||||
|
#undef GET_a
|
||||||
|
#undef UNCOMPRESS_PIX_START
|
||||||
|
#undef UPDATE_MODEL_COMP
|
||||||
|
#undef APPLY_ALL_COMP
|
||||||
|
#undef DECLARE_STATE_VARIABLES
|
||||||
|
#undef DECLARE_CHANNEL_VARIABLES
|
||||||
|
#undef COPY_PIXEL
|
||||||
1
common/recorder
Submodule
1
common/recorder
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d5cbf6caba60d580401c72d0cd18c316cf1be211
|
||||||
106
common/recorder.h
Normal file
106
common/recorder.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
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,17 +16,16 @@
|
|||||||
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_RECT
|
#ifndef H_SPICE_COMMON_RECT
|
||||||
#define _H_RECT
|
#define H_SPICE_COMMON_RECT
|
||||||
|
|
||||||
#include "draw.h"
|
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
#include "draw.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
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);
|
||||||
@ -37,7 +36,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;
|
||||||
@ -45,24 +44,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);
|
||||||
@ -70,15 +69,29 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
static inline int rect_contains(const SpiceRect *big_rect, const SpiceRect *small_rect)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|
||||||
@ -117,6 +130,21 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
static inline int rect_contains(const SpiceRect& big_rect, const SpiceRect& small_rect)
|
||||||
|
{
|
||||||
|
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
|
||||||
@ -15,9 +15,7 @@
|
|||||||
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>
|
||||||
@ -386,6 +384,17 @@ 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)
|
||||||
{
|
{
|
||||||
@ -409,7 +418,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 *)rgn1);
|
extents2 = pixman_region32_extents((pixman_region32_t *)rgn2);
|
||||||
|
|
||||||
return EXTENTCHECK(extents1, extents2);
|
return EXTENTCHECK(extents1, extents2);
|
||||||
}
|
}
|
||||||
@ -441,6 +450,7 @@ 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,
|
||||||
@ -510,381 +520,3 @@ 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,21 +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_REGION
|
#ifndef H_SPICE_COMMON_REGION
|
||||||
#define _H_REGION
|
#define H_SPICE_COMMON_REGION
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "draw.h"
|
#include <spice/macros.h>
|
||||||
#include <pixman_utils.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include "draw.h"
|
||||||
extern "C" {
|
#include "pixman_utils.h"
|
||||||
#endif
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
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)
|
||||||
@ -41,6 +44,7 @@ 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);
|
||||||
@ -61,10 +65,9 @@ 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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -16,14 +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_RING2
|
#ifndef H_SPICE_COMMON_RING
|
||||||
#define _H_RING2
|
#define H_SPICE_COMMON_RING
|
||||||
|
|
||||||
#include "spice_common.h"
|
#include "log.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct Ring RingItem;
|
typedef struct Ring RingItem;
|
||||||
typedef struct Ring {
|
typedef struct Ring {
|
||||||
@ -48,14 +46,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)
|
||||||
{
|
{
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
spice_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)
|
||||||
{
|
{
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
ASSERT(item->next == NULL && item->prev == NULL);
|
spice_assert(item->next == NULL && item->prev == NULL);
|
||||||
|
|
||||||
item->next = ring->next;
|
item->next = ring->next;
|
||||||
item->prev = ring;
|
item->prev = ring;
|
||||||
@ -72,54 +70,43 @@ 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)
|
|
||||||
{
|
|
||||||
item->next->prev = item->prev;
|
|
||||||
item->prev->next = item->next;
|
|
||||||
item->prev = item->next = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ring_remove(RingItem *item)
|
static inline void ring_remove(RingItem *item)
|
||||||
{
|
{
|
||||||
ASSERT(item->next != NULL && item->prev != NULL);
|
spice_assert(item->next != NULL && item->prev != NULL);
|
||||||
ASSERT(item->next != item);
|
spice_assert(item->next != item);
|
||||||
|
|
||||||
__ring_remove(item);
|
item->next->prev = item->prev;
|
||||||
|
item->prev->next = item->next;
|
||||||
|
item->prev = item->next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline RingItem *ring_get_head(Ring *ring)
|
static inline RingItem *ring_get_head(Ring *ring)
|
||||||
{
|
{
|
||||||
RingItem *ret;
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
|
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
|
||||||
|
|
||||||
if (ring_is_empty(ring)) {
|
if (ring_is_empty(ring)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ret = ring->next;
|
return ring->next;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline RingItem *ring_get_tail(Ring *ring)
|
static inline RingItem *ring_get_tail(Ring *ring)
|
||||||
{
|
{
|
||||||
RingItem *ret;
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
|
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
|
||||||
|
|
||||||
if (ring_is_empty(ring)) {
|
if (ring_is_empty(ring)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ret = ring->prev;
|
return 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;
|
||||||
|
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
ASSERT(pos);
|
spice_assert(pos);
|
||||||
ASSERT(pos->next != NULL && pos->prev != NULL);
|
spice_assert(pos->next != NULL && pos->prev != NULL);
|
||||||
ret = pos->next;
|
ret = pos->next;
|
||||||
return (ret == ring) ? NULL : ret;
|
return (ret == ring) ? NULL : ret;
|
||||||
}
|
}
|
||||||
@ -128,9 +115,9 @@ static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
|
|||||||
{
|
{
|
||||||
RingItem *ret;
|
RingItem *ret;
|
||||||
|
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
ASSERT(pos);
|
spice_assert(pos);
|
||||||
ASSERT(pos->next != NULL && pos->prev != NULL);
|
spice_assert(pos->next != NULL && pos->prev != NULL);
|
||||||
ret = pos->prev;
|
ret = pos->prev;
|
||||||
return (ret == ring) ? NULL : ret;
|
return (ret == ring) ? NULL : ret;
|
||||||
}
|
}
|
||||||
@ -157,16 +144,12 @@ static inline unsigned int ring_get_length(Ring *ring)
|
|||||||
RingItem *i;
|
RingItem *i;
|
||||||
unsigned int ret = 0;
|
unsigned int ret = 0;
|
||||||
|
|
||||||
for (i = ring_get_head(ring);
|
RING_FOREACH(i, ring)
|
||||||
i != NULL;
|
|
||||||
i = ring_next(ring, i))
|
|
||||||
ret++;
|
ret++;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -15,14 +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 "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,
|
||||||
@ -43,17 +38,21 @@ 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(pixman_image_t *d, pixman_image_t *s,
|
static void default_rop3_with_pattern_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
|
||||||
SpicePoint *src_pos, pixman_image_t *p,
|
SPICE_GNUC_UNUSED pixman_image_t *s,
|
||||||
SpicePoint *pat_pos)
|
SPICE_GNUC_UNUSED SpicePoint *src_pos,
|
||||||
|
SPICE_GNUC_UNUSED pixman_image_t *p,
|
||||||
|
SPICE_GNUC_UNUSED SpicePoint *pat_pos)
|
||||||
{
|
{
|
||||||
WARN("not implemented");
|
spice_critical("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_rop3_withe_color_handler(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
static void default_rop3_withe_color_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
|
||||||
uint32_t rgb)
|
SPICE_GNUC_UNUSED pixman_image_t *s,
|
||||||
|
SPICE_GNUC_UNUSED SpicePoint *src_pos,
|
||||||
|
SPICE_GNUC_UNUSED uint32_t rgb)
|
||||||
{
|
{
|
||||||
WARN("not implemented");
|
spice_critical("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_rop3_test_handler(void)
|
static void default_rop3_test_handler(void)
|
||||||
@ -374,16 +373,10 @@ 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;
|
||||||
|
|
||||||
void rop3_init(void)
|
SPICE_CONSTRUCTOR_FUNC(rop3_global_init)
|
||||||
{
|
{
|
||||||
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;
|
||||||
@ -624,8 +617,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);
|
||||||
ASSERT (bpp == spice_pixman_image_get_bpp(s));
|
spice_assert(bpp == spice_pixman_image_get_bpp(s));
|
||||||
ASSERT (bpp == spice_pixman_image_get_bpp(p));
|
spice_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);
|
||||||
@ -640,7 +633,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);
|
||||||
ASSERT (bpp == spice_pixman_image_get_bpp(s));
|
spice_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,27 +16,22 @@
|
|||||||
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_ROP3
|
#ifndef H_SPICE_COMMON_ROP3
|
||||||
#define _H_ROP3
|
#define H_SPICE_COMMON_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"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
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);
|
||||||
|
|
||||||
void rop3_init(void);
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
276
common/snd_codec.c
Normal file
276
common/snd_codec.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
/* -*- 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;
|
||||||
|
}
|
||||||
69
common/snd_codec.h
Normal file
69
common/snd_codec.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/* -*- 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
|
||||||
@ -16,12 +16,11 @@
|
|||||||
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>
|
||||||
@ -29,21 +28,14 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#ifndef SPICE_DEBUG
|
#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
|
||||||
# define SPICE_DEBUG(format, ...)
|
(defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000)
|
||||||
#endif
|
static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1)
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
static int inet_aton(const char* ip, struct in_addr* in_addr)
|
|
||||||
{
|
{
|
||||||
unsigned long addr = inet_addr(ip);
|
return M_ASN1_STRING_data(asn1);
|
||||||
|
|
||||||
if (addr == INADDR_NONE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
in_addr->S_un.S_addr = addr;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -58,36 +50,41 @@ 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)
|
||||||
@ -162,19 +159,14 @@ 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;
|
||||||
|
|
||||||
if (!cert) {
|
spice_return_val_if_fail(hostname != NULL, 0);
|
||||||
SPICE_DEBUG("warning: no cert!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only IpV4 supported
|
if (!cert) {
|
||||||
if (inet_aton(hostname, &addr)) {
|
spice_debug("warning: no cert!");
|
||||||
addr_len = sizeof(struct in_addr);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try matching against:
|
/* try matching against:
|
||||||
@ -200,30 +192,56 @@ 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((char *)ASN1_STRING_data(name->d.dNSName),
|
if (_gnutls_hostname_compare((const char *)ASN1_STRING_get0_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_data(name->d.dNSName));
|
spice_debug("alt name match=%s", ASN1_STRING_get0_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) {
|
||||||
int alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
|
GInetAddress * ip;
|
||||||
|
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)&&
|
|
||||||
!memcmp(ASN1_STRING_data(name->d.iPAddress), &addr, addr_len)) {
|
ip = g_inet_address_new_from_string(hostname);
|
||||||
SPICE_DEBUG("alt name IP match=%s",
|
if (ip == NULL) {
|
||||||
inet_ntoa(*((struct in_addr*)ASN1_STRING_data(name->d.dNSName))));
|
spice_warning("Could not parse hostname: %s", hostname);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,38 +262,41 @@ static int verify_hostname(X509* cert, const char *hostname)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_gnutls_hostname_compare((char*)ASN1_STRING_data(cn_asn1),
|
if (_gnutls_hostname_compare((const char*)ASN1_STRING_get0_data(cn_asn1),
|
||||||
ASN1_STRING_length(cn_asn1),
|
ASN1_STRING_length(cn_asn1),
|
||||||
hostname)) {
|
hostname)) {
|
||||||
SPICE_DEBUG("common name match=%s", (char*)ASN1_STRING_data(cn_asn1));
|
spice_debug("common name match=%s", (char*)ASN1_STRING_get0_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
static 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, *k, *v = NULL;
|
char *key, *val = NULL, *k, *v = NULL;
|
||||||
enum {
|
enum {
|
||||||
KEY,
|
KEY,
|
||||||
VALUE
|
VALUE
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
key = (char*)alloca(strlen(subject));
|
spice_return_val_if_fail(subject != NULL, NULL);
|
||||||
val = (char*)alloca(strlen(subject));
|
spice_return_val_if_fail(nentries != NULL, NULL);
|
||||||
|
|
||||||
|
key = (char*)alloca(strlen(subject)+1);
|
||||||
in_subject = X509_NAME_new();
|
in_subject = X509_NAME_new();
|
||||||
|
|
||||||
if (!in_subject || !key || !val) {
|
if (!in_subject || !key) {
|
||||||
SPICE_DEBUG("failed to allocate");
|
spice_debug("failed to allocate");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +309,7 @@ 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;
|
||||||
@ -307,6 +328,7 @@ 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;
|
||||||
@ -322,7 +344,7 @@ 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;
|
||||||
}
|
}
|
||||||
@ -349,89 +371,145 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
|
static 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verify->in_subject) {
|
in_subject = subject_to_x509_name(verify->subject, &in_entries);
|
||||||
verify->in_subject = subject_to_x509_name(verify->subject, &in_entries);
|
if (!in_subject) {
|
||||||
if (!verify->in_subject) {
|
spice_debug("warning: no in_subject!");
|
||||||
SPICE_DEBUG("warning: no in_subject!");
|
|
||||||
return 0;
|
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, verify->in_subject);
|
ret = X509_NAME_cmp(cert_subject, in_subject);
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0) {
|
||||||
SPICE_DEBUG("subjects match");
|
spice_debug("subjects match");
|
||||||
else
|
} else {
|
||||||
SPICE_DEBUG("subjects mismatch");
|
char *p;
|
||||||
|
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;
|
int depth, err;
|
||||||
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_DEBUG("openssl verify failed at depth=%d", depth);
|
spice_warning("Error in certificate chain verification: %s (num=%d:depth%d:%s)",
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY &&
|
failed_verifications = 0;
|
||||||
verify_pubkey(cert, v->pubkey, v->pubkey_size))
|
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY) {
|
||||||
|
if (verify_pubkey(cert, v->pubkey, v->pubkey_size))
|
||||||
return 1;
|
return 1;
|
||||||
|
else
|
||||||
|
failed_verifications |= SPICE_SSL_VERIFY_OP_PUBKEY;
|
||||||
|
}
|
||||||
|
|
||||||
if (!v->all_preverify_ok || !preverify_ok)
|
if (!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_HOSTNAME &&
|
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT) {
|
||||||
verify_hostname(cert, v->hostname))
|
if (verify_subject(cert, v))
|
||||||
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 (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT &&
|
/* If we reach this code, this means all the tests failed, thus
|
||||||
verify_subject(cert, v))
|
* verification failed
|
||||||
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;
|
||||||
}
|
}
|
||||||
@ -473,9 +551,6 @@ 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,12 +16,16 @@
|
|||||||
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 SSL_VERIFY_H
|
#ifndef H_SPICE_COMMON_SSL_VERIFY
|
||||||
#define SSL_VERIFY_H
|
#define H_SPICE_COMMON_SSL_VERIFY
|
||||||
|
|
||||||
#if defined(WIN32) && !defined(__MINGW32__)
|
#if defined(WIN32)
|
||||||
#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>
|
||||||
@ -29,12 +33,11 @@
|
|||||||
#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>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include <spice/macros.h>
|
||||||
extern "C" {
|
|
||||||
#endif
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPICE_SSL_VERIFY_OP_NONE = 0,
|
SPICE_SSL_VERIFY_OP_NONE = 0,
|
||||||
@ -51,7 +54,6 @@ 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,
|
||||||
@ -60,7 +62,6 @@ 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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
#endif // H_SPICE_COMMON_SSL_VERIFY
|
||||||
#endif // SSL_VERIFY_H
|
|
||||||
@ -15,21 +15,13 @@
|
|||||||
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"
|
||||||
@ -83,15 +75,33 @@ 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:
|
||||||
CANVAS_ERROR("invalid brush type");
|
spice_warn_if_reached();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pixman_image_t *get_image(SpiceCanvas *canvas)
|
static pixman_image_t *get_image(SpiceCanvas *canvas, int force_opaque)
|
||||||
{
|
{
|
||||||
SwCanvas *sw_canvas = (SwCanvas *)canvas;
|
SwCanvas *sw_canvas = (SwCanvas *)canvas;
|
||||||
|
pixman_format_code_t format;
|
||||||
|
|
||||||
|
spice_pixman_image_get_format(sw_canvas->image, &format);
|
||||||
|
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);
|
pixman_image_ref(sw_canvas->image);
|
||||||
|
}
|
||||||
|
|
||||||
return sw_canvas->image;
|
return sw_canvas->image;
|
||||||
}
|
}
|
||||||
@ -343,7 +353,7 @@ static void clear_dest_alpha(pixman_image_t *dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
stride = pixman_image_get_stride(dest);
|
stride = pixman_image_get_stride(dest);
|
||||||
data = (uint32_t *) (
|
data = SPICE_ALIGNED_CAST(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) {
|
||||||
@ -477,7 +487,7 @@ static void __scale_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
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);
|
||||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
spice_return_if_fail(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) ?
|
||||||
@ -539,11 +549,13 @@ 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;
|
||||||
|
|
||||||
scaled = pixman_image_create_bits(spice_pixman_image_get_format(src),
|
spice_return_if_fail(spice_pixman_image_get_format(src, &format));
|
||||||
|
scaled = pixman_image_create_bits(format,
|
||||||
dest_width,
|
dest_width,
|
||||||
dest_height,
|
dest_height,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
@ -558,7 +570,7 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
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);
|
||||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
spice_return_if_fail(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) ?
|
||||||
@ -659,7 +671,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 };
|
pixman_color_t color = { 0, 0, 0, 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);
|
||||||
}
|
}
|
||||||
@ -752,14 +764,14 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
if (overall_alpha != 0xff) {
|
if (overall_alpha != 0xff) {
|
||||||
pixman_color_t color = { 0 };
|
pixman_color_t color = { 0, 0, 0, 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);
|
||||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
spice_return_if_fail(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) ?
|
||||||
@ -895,11 +907,13 @@ 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;
|
||||||
|
|
||||||
scaled = pixman_image_create_bits(spice_pixman_image_get_format (src),
|
spice_return_if_fail(spice_pixman_image_get_format(src, &format));
|
||||||
|
scaled = pixman_image_create_bits(format,
|
||||||
dest_width,
|
dest_width,
|
||||||
dest_height,
|
dest_height,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
@ -977,9 +991,6 @@ 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)
|
||||||
@ -994,7 +1005,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,
|
||||||
(uint32_t*)src_data,
|
SPICE_ALIGNED_CAST(uint32_t*,src_data),
|
||||||
src_stride);
|
src_stride);
|
||||||
|
|
||||||
|
|
||||||
@ -1042,7 +1053,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;
|
SpicePoint pos = { 0, 0 };
|
||||||
int depth;
|
int depth;
|
||||||
|
|
||||||
pixman_region32_init_rect(&dest_region,
|
pixman_region32_init_rect(&dest_region,
|
||||||
@ -1064,7 +1075,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 */
|
||||||
ASSERT(text->fore_mode == SPICE_ROPD_OP_PUT);
|
spice_return_if_fail(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,
|
||||||
@ -1087,10 +1098,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) {
|
||||||
WARN("untested path A8 glyphs");
|
spice_warning("untested path A8 glyphs");
|
||||||
depth = 8;
|
depth = 8;
|
||||||
} else {
|
} else {
|
||||||
WARN("unsupported path vector glyphs");
|
spice_warning("unsupported path vector glyphs");
|
||||||
pixman_region32_fini (&dest_region);
|
pixman_region32_fini (&dest_region);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1133,7 +1144,7 @@ static void canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest,
|
|||||||
uint8_t *dest_end;
|
uint8_t *dest_end;
|
||||||
int bpp;
|
int bpp;
|
||||||
|
|
||||||
ASSERT(canvas && area);
|
spice_return_if_fail(canvas && area);
|
||||||
|
|
||||||
surface = canvas->image;
|
surface = canvas->image;
|
||||||
|
|
||||||
@ -1170,28 +1181,21 @@ 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
|
||||||
, 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,
|
||||||
, 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));
|
||||||
|
|
||||||
@ -1199,18 +1203,15 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
|||||||
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
|
||||||
, bits_cache
|
palette_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;
|
||||||
|
|
||||||
@ -1219,78 +1220,37 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
|||||||
return (SpiceCanvas *)canvas;
|
return (SpiceCanvas *)canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
{
|
|
||||||
pixman_image_t *image;
|
|
||||||
|
|
||||||
image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
|
|
||||||
width, height, NULL, 0);
|
|
||||||
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
|
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
|
||||||
uint8_t *data, int stride
|
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,
|
||||||
, 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, (uint32_t *)data, stride);
|
width, height,
|
||||||
|
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
|
||||||
, bits_cache
|
palette_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);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sw_canvas_init(void) //unsafe global function
|
SPICE_CONSTRUCTOR_FUNC(sw_canvas_global_init) //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;
|
||||||
@ -1323,5 +1283,4 @@ void sw_canvas_init(void) //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,38 +16,31 @@
|
|||||||
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/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "glc.h"
|
#ifndef H_SPICE_COMMON_SW_CANVAS
|
||||||
|
#define H_SPICE_COMMON_SW_CANVAS
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
#include "draw.h"
|
||||||
|
#include "pixman_utils.h"
|
||||||
#include "canvas_base.h"
|
#include "canvas_base.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
|
|
||||||
#ifndef SPICE_CANVAS_INTERNAL
|
SPICE_BEGIN_DECLS
|
||||||
#error "This header shouldn't be included directly"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _H__GL_CANVAS
|
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, int stride
|
||||||
#define _H__GL_CANVAS
|
, SpiceImageCache *bits_cache
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
|
|
||||||
#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
|
||||||
, SpiceJpegDecoder *jpeg_decoder
|
, SpiceJpegDecoder *jpeg_decoder
|
||||||
, SpiceZlibDecoder *zlib_decoder
|
, SpiceZlibDecoder *zlib_decoder
|
||||||
);
|
);
|
||||||
void gl_canvas_set_textures_lost(SpiceCanvas *canvas, int textures_lost);
|
|
||||||
void gl_canvas_init(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
SPICE_END_DECLS
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
78
common/udev.c
Normal file
78
common/udev.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
33
common/udev.h
Normal file
33
common/udev.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
66
common/utils.c
Normal file
66
common/utils.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* -*- 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);
|
||||||
|
}
|
||||||
57
common/utils.h
Normal file
57
common/utils.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/* -*- 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
Normal file
283
common/verify.h
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
/* 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
|
||||||
81
configure.ac
Normal file
81
configure.ac
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
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
|
||||||
27
docs/Makefile.am
Normal file
27
docs/Makefile.am
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
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
|
||||||
12
docs/meson.build
Normal file
12
docs/meson.build
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
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
|
||||||
477
docs/spice_protocol.txt
Normal file
477
docs/spice_protocol.txt
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
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
|
||||||
131
docs/spice_uri_scheme.txt
Normal file
131
docs/spice_uri_scheme.txt
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
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.
|
||||||
1858
gdi_canvas.c
1858
gdi_canvas.c
File diff suppressed because it is too large
Load Diff
51
gdi_canvas.h
51
gdi_canvas.h
@ -1,51 +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__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
|
|
||||||
400
git.mk
Normal file
400
git.mk
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
# 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
|
||||||
906
gl_canvas.c
906
gl_canvas.c
@ -1,906 +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/>.
|
|
||||||
*/
|
|
||||||
#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();
|
|
||||||
}
|
|
||||||
61
gl_utils.h
61
gl_utils.h
@ -1,61 +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, 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
|
|
||||||
167
glc.h
167
glc.h
@ -1,167 +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, 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
|
|
||||||
0
m4/.gitignore
vendored
Normal file
0
m4/.gitignore
vendored
Normal file
49
m4/ax_python_module.m4
Normal file
49
m4/ax_python_module.m4
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# ===========================================================================
|
||||||
|
# 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
|
||||||
|
])
|
||||||
6
m4/common.m4
Normal file
6
m4/common.m4
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
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
Normal file
368
m4/spice-deps.m4
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
# 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
|
||||||
|
])
|
||||||
32
m4/spice_manual.m4
Normal file
32
m4/spice_manual.m4
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
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
Normal file
181
meson.build
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#
|
||||||
|
# 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)
|
||||||
54
meson_options.txt
Normal file
54
meson_options.txt
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
option('alignment-checks',
|
||||||
|
type : 'boolean',
|
||||||
|
value : false,
|
||||||
|
yield : true,
|
||||||
|
description : 'Enable runtime checks for cast alignment')
|
||||||
|
|
||||||
|
option('extra-checks',
|
||||||
|
type : 'boolean',
|
||||||
|
value : false,
|
||||||
|
yield : true,
|
||||||
|
description : 'Enable extra checks on code')
|
||||||
|
|
||||||
|
option('opus',
|
||||||
|
type : 'feature',
|
||||||
|
yield : true,
|
||||||
|
description: 'Enable Opus audio codec')
|
||||||
|
|
||||||
|
option('instrumentation',
|
||||||
|
type : 'combo',
|
||||||
|
value : 'no',
|
||||||
|
choices : ['recorder', 'agent', 'no'],
|
||||||
|
description: 'Enable instrumentation')
|
||||||
|
|
||||||
|
option('smartcard',
|
||||||
|
type : 'feature',
|
||||||
|
yield : true,
|
||||||
|
description : 'Enable smartcard support')
|
||||||
|
|
||||||
|
option('python-checks',
|
||||||
|
type : 'boolean',
|
||||||
|
value : true,
|
||||||
|
description : 'Enable checks for Python modules needed to build from git')
|
||||||
|
|
||||||
|
option('manual',
|
||||||
|
type : 'boolean',
|
||||||
|
value : true,
|
||||||
|
yield : true,
|
||||||
|
description : 'Build SPICE manual')
|
||||||
|
|
||||||
|
option('generate-code',
|
||||||
|
type : 'combo',
|
||||||
|
choices : ['all', 'server', 'client', 'none'],
|
||||||
|
description : 'Which code should be built')
|
||||||
|
|
||||||
|
option('tests',
|
||||||
|
type : 'boolean',
|
||||||
|
value : true,
|
||||||
|
yield : true,
|
||||||
|
description : 'Enable SPICE tests')
|
||||||
|
|
||||||
|
option('spice-protocol-version',
|
||||||
|
type : 'string',
|
||||||
|
value : '0.1', # not existing low number version
|
||||||
|
description : 'Minimal requested SPICE protocol version')
|
||||||
525
messages.h
525
messages.h
@ -1,525 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2009-2010 Red Hat, Inc.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in
|
|
||||||
the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
|
|
||||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _H_MESSAGES
|
|
||||||
#define _H_MESSAGES
|
|
||||||
|
|
||||||
#include <spice/protocol.h>
|
|
||||||
#include "draw.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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;
|
|
||||||
uint64_t id;
|
|
||||||
} SpiceResourceID;
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainAgentTokens {
|
|
||||||
uint32_t num_tokens;
|
|
||||||
} SpiceMsgMainAgentTokens, SpiceMsgcMainAgentTokens, SpiceMsgcMainAgentStart;
|
|
||||||
|
|
||||||
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];
|
|
||||||
} 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 /* _H_SPICE_PROTOCOL */
|
|
||||||
44
mutex.h
44
mutex.h
@ -1,44 +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_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
ogl_ctx.c
251
ogl_ctx.c
@ -1,251 +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/>.
|
|
||||||
*/
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
16
python_modules/Makefile.am
Normal file
16
python_modules/Makefile.am
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
NULL =
|
||||||
|
|
||||||
|
PYTHON_MODULES = \
|
||||||
|
__init__.py \
|
||||||
|
codegen.py \
|
||||||
|
demarshal.py \
|
||||||
|
marshal.py \
|
||||||
|
ptypes.py \
|
||||||
|
spice_parser.py \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
EXTRA_DIST = meson.build $(PYTHON_MODULES)
|
||||||
|
|
||||||
|
DISTCLEANFILES = *.pyc __pycache__/*.pyc
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
||||||
0
python_modules/__init__.py
Normal file
0
python_modules/__init__.py
Normal file
376
python_modules/codegen.py
Normal file
376
python_modules/codegen.py
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
def camel_to_underscores(s, upper = False):
|
||||||
|
res = ""
|
||||||
|
for i in range(len(s)):
|
||||||
|
c = s[i]
|
||||||
|
if i > 0 and c.isupper():
|
||||||
|
res = res + "_"
|
||||||
|
if upper:
|
||||||
|
res = res + c.upper()
|
||||||
|
else:
|
||||||
|
res = res + c.lower()
|
||||||
|
return res
|
||||||
|
|
||||||
|
def underscores_to_camel(s):
|
||||||
|
res = ""
|
||||||
|
do_upper = True
|
||||||
|
for i in range(len(s)):
|
||||||
|
c = s[i]
|
||||||
|
if c == "_":
|
||||||
|
do_upper = True
|
||||||
|
else:
|
||||||
|
if do_upper:
|
||||||
|
res = res + c.upper()
|
||||||
|
else:
|
||||||
|
res = res + c
|
||||||
|
do_upper = False
|
||||||
|
return res
|
||||||
|
|
||||||
|
proto_prefix = "Temp"
|
||||||
|
|
||||||
|
def set_prefix(prefix):
|
||||||
|
global proto_prefix
|
||||||
|
global proto_prefix_upper
|
||||||
|
global proto_prefix_lower
|
||||||
|
proto_prefix = prefix
|
||||||
|
proto_prefix_upper = prefix.upper()
|
||||||
|
proto_prefix_lower = prefix.lower()
|
||||||
|
|
||||||
|
def prefix_underscore_upper(*args):
|
||||||
|
s = proto_prefix_upper
|
||||||
|
for arg in args:
|
||||||
|
s = s + "_" + arg
|
||||||
|
return s
|
||||||
|
|
||||||
|
def prefix_underscore_lower(*args):
|
||||||
|
s = proto_prefix_lower
|
||||||
|
for arg in args:
|
||||||
|
s = s + "_" + arg
|
||||||
|
return s
|
||||||
|
|
||||||
|
def prefix_camel(*args):
|
||||||
|
s = proto_prefix
|
||||||
|
for arg in args:
|
||||||
|
s = s + underscores_to_camel(arg)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def increment_identifier(idf):
|
||||||
|
v = idf[-1:]
|
||||||
|
if v.isdigit():
|
||||||
|
return idf[:-1] + str(int(v) + 1)
|
||||||
|
return idf + "2"
|
||||||
|
|
||||||
|
def sum_array(array):
|
||||||
|
if len(array) == 0:
|
||||||
|
return 0
|
||||||
|
return " + ".join(array)
|
||||||
|
|
||||||
|
class CodeWriter:
|
||||||
|
def __init__(self):
|
||||||
|
self.out = StringIO()
|
||||||
|
self.contents = [self.out]
|
||||||
|
self.indentation = 0
|
||||||
|
self.at_line_start = True
|
||||||
|
self.indexes = ["i", "j", "k", "ii", "jj", "kk"]
|
||||||
|
self.current_index = 0
|
||||||
|
self.generated = {}
|
||||||
|
self.vars = []
|
||||||
|
self.has_error_check = False
|
||||||
|
self.options = {}
|
||||||
|
self.function_helper_writer = None
|
||||||
|
self.index_type = 'uint32_t'
|
||||||
|
|
||||||
|
def set_option(self, opt, value = True):
|
||||||
|
self.options[opt] = value
|
||||||
|
|
||||||
|
def has_option(self, opt):
|
||||||
|
return opt in self.options
|
||||||
|
|
||||||
|
def set_is_generated(self, kind, name):
|
||||||
|
if kind not in self.generated:
|
||||||
|
v = {}
|
||||||
|
self.generated[kind] = v
|
||||||
|
else:
|
||||||
|
v = self.generated[kind]
|
||||||
|
v[name] = 1
|
||||||
|
|
||||||
|
def is_generated(self, kind, name):
|
||||||
|
if kind not in self.generated:
|
||||||
|
return False
|
||||||
|
v = self.generated[kind]
|
||||||
|
return name in v
|
||||||
|
|
||||||
|
def getvalue(self):
|
||||||
|
strs = [writer.getvalue() for writer in self.contents]
|
||||||
|
return "".join(strs)
|
||||||
|
|
||||||
|
def get_subwriter(self):
|
||||||
|
writer = CodeWriter()
|
||||||
|
self.contents.append(writer)
|
||||||
|
self.out = StringIO()
|
||||||
|
self.contents.append(self.out)
|
||||||
|
writer.indentation = self.indentation
|
||||||
|
writer.at_line_start = self.at_line_start
|
||||||
|
writer.index_type = self.index_type
|
||||||
|
writer.generated = self.generated
|
||||||
|
writer.options = self.options
|
||||||
|
writer.public_suffix = self.public_suffix
|
||||||
|
|
||||||
|
return writer
|
||||||
|
|
||||||
|
def write(self, s):
|
||||||
|
# Ensure its a unicode string
|
||||||
|
s = str(s)
|
||||||
|
|
||||||
|
if len(s) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.at_line_start:
|
||||||
|
self.out.write(" " * self.indentation)
|
||||||
|
self.at_line_start = False
|
||||||
|
self.out.write(s)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def newline(self):
|
||||||
|
self.out.write("\n")
|
||||||
|
self.at_line_start = True
|
||||||
|
return self
|
||||||
|
|
||||||
|
def writeln(self, s):
|
||||||
|
self.write(s)
|
||||||
|
self.newline()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def label(self, s):
|
||||||
|
self.indentation = self.indentation - 1
|
||||||
|
self.write(s + ":")
|
||||||
|
self.indentation = self.indentation + 1
|
||||||
|
self.newline()
|
||||||
|
|
||||||
|
def statement(self, s):
|
||||||
|
self.write(s)
|
||||||
|
self.write(";")
|
||||||
|
self.newline()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def assign(self, var, val):
|
||||||
|
self.write("%s = %s" % (var, val))
|
||||||
|
self.write(";")
|
||||||
|
self.newline()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def increment(self, var, val):
|
||||||
|
self.write("%s += %s" % (var, val))
|
||||||
|
self.write(";")
|
||||||
|
self.newline()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def comment(self, str):
|
||||||
|
self.write("/* " + str + " */")
|
||||||
|
return self
|
||||||
|
|
||||||
|
def todo(self, str):
|
||||||
|
self.comment("TODO: *** %s ***" % str).newline()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def error_check(self, check, label = "error"):
|
||||||
|
self.has_error_check = True
|
||||||
|
with self.block("if (SPICE_UNLIKELY(%s))" % check):
|
||||||
|
if self.has_option("print_error"):
|
||||||
|
self.statement('printf("%%s: Caught error - %s", __PRETTY_FUNCTION__)' % check)
|
||||||
|
if self.has_option("assert_on_error"):
|
||||||
|
self.statement("assert(0)")
|
||||||
|
self.statement("goto %s" % label)
|
||||||
|
|
||||||
|
def indent(self):
|
||||||
|
self.indentation += 4
|
||||||
|
|
||||||
|
def unindent(self):
|
||||||
|
self.indentation -= 4
|
||||||
|
if self.indentation < 0:
|
||||||
|
self.indentation = 0
|
||||||
|
|
||||||
|
def begin_block(self, prefix= "", comment = ""):
|
||||||
|
if len(prefix) > 0:
|
||||||
|
self.write(prefix)
|
||||||
|
if self.at_line_start:
|
||||||
|
self.write("{")
|
||||||
|
else:
|
||||||
|
self.write(" {")
|
||||||
|
if len(comment) > 0:
|
||||||
|
self.write(" ")
|
||||||
|
self.comment(comment)
|
||||||
|
self.newline()
|
||||||
|
self.indent()
|
||||||
|
|
||||||
|
def end_block(self, semicolon=False, newline=True):
|
||||||
|
self.unindent()
|
||||||
|
if self.at_line_start:
|
||||||
|
self.write("}")
|
||||||
|
else:
|
||||||
|
self.write(" }")
|
||||||
|
if semicolon:
|
||||||
|
self.write(";")
|
||||||
|
if newline:
|
||||||
|
self.newline()
|
||||||
|
|
||||||
|
class Block:
|
||||||
|
def __init__(self, writer, semicolon, newline):
|
||||||
|
self.writer = writer
|
||||||
|
self.semicolon = semicolon
|
||||||
|
self.newline = newline
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self.writer.get_subwriter()
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.writer.end_block(self.semicolon, self.newline)
|
||||||
|
|
||||||
|
class PartialBlock:
|
||||||
|
def __init__(self, writer, scope, semicolon, newline):
|
||||||
|
self.writer = writer
|
||||||
|
self.scope = scope
|
||||||
|
self.semicolon = semicolon
|
||||||
|
self.newline = newline
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self.scope
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.writer.end_block(self.semicolon, self.newline)
|
||||||
|
|
||||||
|
class NoBlock:
|
||||||
|
def __init__(self, scope):
|
||||||
|
self.scope = scope
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self.scope
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def block(self, prefix= "", comment = "", semicolon=False, newline=True):
|
||||||
|
self.begin_block(prefix, comment)
|
||||||
|
return self.Block(self, semicolon, newline)
|
||||||
|
|
||||||
|
def partial_block(self, scope, semicolon=False, newline=True):
|
||||||
|
return self.PartialBlock(self, scope, semicolon, newline)
|
||||||
|
|
||||||
|
def no_block(self, scope):
|
||||||
|
return self.NoBlock(scope)
|
||||||
|
|
||||||
|
def optional_block(self, scope):
|
||||||
|
if scope != None:
|
||||||
|
return self.NoBlock(scope)
|
||||||
|
return self.block()
|
||||||
|
|
||||||
|
def for_loop(self, index, limit):
|
||||||
|
return self.block("for (%s = 0; %s < %s; %s++)" % (index, index, limit, index))
|
||||||
|
|
||||||
|
def while_loop(self, expr):
|
||||||
|
return self.block("while (%s)" % (expr))
|
||||||
|
|
||||||
|
def if_block(self, check, elseif=False, newline=True):
|
||||||
|
s = "if (%s)" % (check)
|
||||||
|
if elseif:
|
||||||
|
s = " else " + s
|
||||||
|
self.begin_block(s, "")
|
||||||
|
return self.Block(self, False, newline)
|
||||||
|
|
||||||
|
def variable_defined(self, name):
|
||||||
|
for n in self.vars:
|
||||||
|
if n == name:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def variable_def(self, ctype, *names):
|
||||||
|
for n in names:
|
||||||
|
# Strip away initialization
|
||||||
|
i = n.find("=")
|
||||||
|
if i != -1:
|
||||||
|
n = n[0:i]
|
||||||
|
self.vars.append(n.strip())
|
||||||
|
# only add space for non-pointer types
|
||||||
|
if ctype[-1] == "*":
|
||||||
|
ctype = ctype[:-1].rstrip()
|
||||||
|
self.writeln("%s *%s;"%(ctype, ", *".join(names)))
|
||||||
|
else:
|
||||||
|
self.writeln("%s %s;"%(ctype, ", ".join(names)))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def function_helper(self):
|
||||||
|
if self.function_helper_writer != None:
|
||||||
|
writer = self.function_helper_writer.get_subwriter()
|
||||||
|
self.function_helper_writer.newline()
|
||||||
|
else:
|
||||||
|
writer = self.get_subwriter()
|
||||||
|
return writer
|
||||||
|
|
||||||
|
def function(self, name, return_type, args, static = False):
|
||||||
|
self.has_error_check = False
|
||||||
|
self.function_helper_writer = self.get_subwriter()
|
||||||
|
if static:
|
||||||
|
self.write("static ")
|
||||||
|
self.write(return_type)
|
||||||
|
self.write(" %s(%s)"% (name, args)).newline()
|
||||||
|
self.begin_block()
|
||||||
|
self.function_variables_writer = self.get_subwriter()
|
||||||
|
self.function_variables = {}
|
||||||
|
return self.function_variables_writer
|
||||||
|
|
||||||
|
def macro(self, name, args, define):
|
||||||
|
self.write("#define %s(%s) %s" % (name, args, define)).newline()
|
||||||
|
|
||||||
|
def ifdef(self, name):
|
||||||
|
indentation = self.indentation
|
||||||
|
self.indentation = 0;
|
||||||
|
self.write("#ifdef %s" % (name)).newline()
|
||||||
|
self.indentation = indentation
|
||||||
|
|
||||||
|
def ifdef_else(self, name):
|
||||||
|
indentation = self.indentation
|
||||||
|
self.indentation = 0;
|
||||||
|
self.write("#else /* %s */" % (name)).newline()
|
||||||
|
self.indentation = indentation
|
||||||
|
|
||||||
|
def endif(self, name):
|
||||||
|
indentation = self.indentation
|
||||||
|
self.indentation = 0;
|
||||||
|
self.write("#endif /* %s */" % (name)).newline()
|
||||||
|
self.indentation = indentation
|
||||||
|
|
||||||
|
def add_function_variable(self, ctype, name):
|
||||||
|
if name in self.function_variables:
|
||||||
|
assert(self.function_variables[name] == ctype)
|
||||||
|
else:
|
||||||
|
self.function_variables[name] = ctype
|
||||||
|
self.function_variables_writer.variable_def(ctype, name)
|
||||||
|
|
||||||
|
def pop_index(self):
|
||||||
|
index = self.indexes[self.current_index]
|
||||||
|
self.current_index = self.current_index + 1
|
||||||
|
self.add_function_variable(self.index_type, index)
|
||||||
|
return index
|
||||||
|
|
||||||
|
def push_index(self):
|
||||||
|
assert self.current_index > 0
|
||||||
|
self.current_index = self.current_index - 1
|
||||||
|
|
||||||
|
class Index:
|
||||||
|
def __init__(self, writer, val):
|
||||||
|
self.writer = writer
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self.val
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.writer.push_index()
|
||||||
|
|
||||||
|
def index(self, no_block = False):
|
||||||
|
if no_block:
|
||||||
|
return self.no_block(None)
|
||||||
|
val = self.pop_index()
|
||||||
|
return self.Index(self, val)
|
||||||
1237
python_modules/demarshal.py
Normal file
1237
python_modules/demarshal.py
Normal file
File diff suppressed because it is too large
Load Diff
430
python_modules/marshal.py
Normal file
430
python_modules/marshal.py
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
|
||||||
|
from . import ptypes
|
||||||
|
from . import codegen
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
def write_includes(writer):
|
||||||
|
writer.header.writeln("#include <spice/protocol.h>")
|
||||||
|
writer.header.writeln('#include "common/marshaller.h"')
|
||||||
|
writer.header.newline()
|
||||||
|
if writer.header.has_option("dest_file"):
|
||||||
|
src = os.path.basename(writer.header.options["dest_file"])
|
||||||
|
else:
|
||||||
|
src = "generated_headers.h"
|
||||||
|
src = re.sub(r'(?i)[^a-z0-9]+', '_', src)
|
||||||
|
src = src.upper()
|
||||||
|
if src.endswith("_H"):
|
||||||
|
src = "_H_"+src[:-2]
|
||||||
|
writer.header.writeln("#ifndef %s" % src)
|
||||||
|
writer.header.writeln("#define %s" % src)
|
||||||
|
writer.header.newline()
|
||||||
|
writer.header.writeln("SPICE_BEGIN_DECLS")
|
||||||
|
writer.header.newline()
|
||||||
|
|
||||||
|
writer.writeln("#include <string.h>")
|
||||||
|
writer.writeln("#include <assert.h>")
|
||||||
|
writer.writeln("#include <stdlib.h>")
|
||||||
|
writer.writeln("#include <stdio.h>")
|
||||||
|
writer.writeln("#include <spice/protocol.h>")
|
||||||
|
writer.writeln("#include <spice/macros.h>")
|
||||||
|
writer.writeln('#include "common/marshaller.h"')
|
||||||
|
writer.newline()
|
||||||
|
writer.writeln("#ifdef _MSC_VER")
|
||||||
|
writer.writeln("#pragma warning(disable:4101)")
|
||||||
|
writer.writeln("#pragma warning(disable:4018)")
|
||||||
|
writer.writeln("#endif")
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
class MarshallingSource:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def child_at_end(self, t):
|
||||||
|
return RootMarshallingSource(self, t.c_type(), t.sizeof())
|
||||||
|
|
||||||
|
def child_sub(self, containee):
|
||||||
|
return SubMarshallingSource(self, containee)
|
||||||
|
|
||||||
|
def declare(self, writer):
|
||||||
|
return writer.optional_block(self.reuse_scope)
|
||||||
|
|
||||||
|
def is_toplevel(self):
|
||||||
|
return self.parent_src == None and not self.is_helper
|
||||||
|
|
||||||
|
class RootMarshallingSource(MarshallingSource):
|
||||||
|
def __init__(self, parent_src, c_type, sizeof, pointer = None):
|
||||||
|
self.is_helper = False
|
||||||
|
self.reuse_scope = None
|
||||||
|
self.parent_src = parent_src
|
||||||
|
if parent_src:
|
||||||
|
self.base_var = codegen.increment_identifier(parent_src.base_var)
|
||||||
|
else:
|
||||||
|
self.base_var = "src"
|
||||||
|
self.c_type = c_type
|
||||||
|
self.sizeof = sizeof
|
||||||
|
self.pointer = pointer
|
||||||
|
assert pointer != None
|
||||||
|
|
||||||
|
def get_self_ref(self):
|
||||||
|
return self.base_var
|
||||||
|
|
||||||
|
def get_ref(self, member):
|
||||||
|
return self.base_var + "->" + member
|
||||||
|
|
||||||
|
def declare(self, writer):
|
||||||
|
if self.reuse_scope:
|
||||||
|
scope = self.reuse_scope
|
||||||
|
else:
|
||||||
|
writer.begin_block()
|
||||||
|
scope = writer.get_subwriter()
|
||||||
|
|
||||||
|
scope.variable_def("const " + self.c_type + " *", self.base_var)
|
||||||
|
if not self.reuse_scope:
|
||||||
|
scope.newline()
|
||||||
|
|
||||||
|
writer.assign(self.base_var, "(const %s *)%s" % (self.c_type, self.pointer))
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
if self.reuse_scope:
|
||||||
|
return writer.no_block(self.reuse_scope)
|
||||||
|
else:
|
||||||
|
return writer.partial_block(scope)
|
||||||
|
|
||||||
|
class SubMarshallingSource(MarshallingSource):
|
||||||
|
def __init__(self, parent_src, containee):
|
||||||
|
self.reuse_scope = None
|
||||||
|
self.parent_src = parent_src
|
||||||
|
self.base_var = parent_src.base_var
|
||||||
|
self.containee = containee
|
||||||
|
self.name = containee.name
|
||||||
|
self.is_helper = False
|
||||||
|
|
||||||
|
def get_self_ref(self):
|
||||||
|
if self.containee.has_attr("to_ptr"):
|
||||||
|
return "%s" % self.parent_src.get_ref(self.name)
|
||||||
|
else:
|
||||||
|
return "&%s" % self.parent_src.get_ref(self.name)
|
||||||
|
|
||||||
|
def get_ref(self, member):
|
||||||
|
if self.containee.has_attr("to_ptr"):
|
||||||
|
return self.parent_src.get_ref(self.name) + "->" + member
|
||||||
|
else:
|
||||||
|
return self.parent_src.get_ref(self.name) + "." + member
|
||||||
|
|
||||||
|
def write_marshal_ptr_function(writer, target_type, is_helper=True):
|
||||||
|
if target_type.is_array():
|
||||||
|
marshal_function = "spice_marshall_array_%s" % target_type.element_type.primitive_type()
|
||||||
|
else:
|
||||||
|
marshal_function = "spice_marshall_%s" % target_type.name
|
||||||
|
if writer.is_generated("marshaller", marshal_function):
|
||||||
|
return marshal_function
|
||||||
|
|
||||||
|
writer.set_is_generated("marshaller", marshal_function)
|
||||||
|
|
||||||
|
names = target_type.get_pointer_names(False)
|
||||||
|
names_args = ""
|
||||||
|
if len(names) > 0:
|
||||||
|
n = [", SpiceMarshaller **%s_out" % name for name in names]
|
||||||
|
names_args = "".join(n)
|
||||||
|
|
||||||
|
header = writer.header
|
||||||
|
if is_helper:
|
||||||
|
writer = writer.function_helper()
|
||||||
|
writer.header = header
|
||||||
|
writer.out_prefix = ""
|
||||||
|
if target_type.is_array():
|
||||||
|
scope = writer.function(marshal_function, "SPICE_GNUC_UNUSED static void",
|
||||||
|
"SpiceMarshaller *m, const %s_t *ptr, unsigned count" % target_type.element_type.primitive_type() + names_args)
|
||||||
|
else:
|
||||||
|
scope = writer.function(marshal_function, "void", "SpiceMarshaller *m, const %s *ptr" % target_type.c_type() + names_args)
|
||||||
|
header.writeln("void " + marshal_function + "(SpiceMarshaller *m, const %s *msg" % target_type.c_type() + names_args + ");")
|
||||||
|
scope.variable_def("SPICE_GNUC_UNUSED SpiceMarshaller *", "m2")
|
||||||
|
|
||||||
|
for n in names:
|
||||||
|
writer.assign("*%s_out" % n, "NULL")
|
||||||
|
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
if target_type.is_struct():
|
||||||
|
src = RootMarshallingSource(None, target_type.c_type(), target_type.sizeof(), "ptr")
|
||||||
|
src.reuse_scope = scope
|
||||||
|
write_container_marshaller(writer, target_type, src)
|
||||||
|
elif target_type.is_array() and target_type.element_type.is_primitive():
|
||||||
|
with writer.index() as index:
|
||||||
|
with writer.for_loop(index, "count") as array_scope:
|
||||||
|
writer.statement("spice_marshaller_add_%s(m, *ptr++)" % (target_type.element_type.primitive_type()))
|
||||||
|
else:
|
||||||
|
writer.todo("Unsuppored pointer marshaller type")
|
||||||
|
|
||||||
|
writer.end_block()
|
||||||
|
|
||||||
|
return marshal_function
|
||||||
|
|
||||||
|
def get_array_size(array, container_src):
|
||||||
|
if array.is_constant_length():
|
||||||
|
return array.size
|
||||||
|
elif array.is_identifier_length():
|
||||||
|
return container_src.get_ref(array.size)
|
||||||
|
elif array.is_remaining_length():
|
||||||
|
raise NotImplementedError("remaining size array sizes marshalling not supported")
|
||||||
|
elif array.is_image_size_length():
|
||||||
|
bpp = array.size[1]
|
||||||
|
width = array.size[2]
|
||||||
|
rows = array.size[3]
|
||||||
|
width_v = container_src.get_ref(width)
|
||||||
|
rows_v = container_src.get_ref(rows)
|
||||||
|
if bpp == 8:
|
||||||
|
return "((uint64_t) %s * %s)" % (width_v, rows_v)
|
||||||
|
elif bpp == 1:
|
||||||
|
return "((((uint64_t) %s + 7U) / 8U ) * %s)" % (width_v, rows_v)
|
||||||
|
else:
|
||||||
|
return "((((uint64_t) %s * %s + 7U) / 8U ) * %s)" % (bpp, width_v, rows_v)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError("TODO array size type not handled yet: %s" % array)
|
||||||
|
|
||||||
|
def write_array_marshaller(writer, member, array, container_src, scope):
|
||||||
|
element_type = array.element_type
|
||||||
|
|
||||||
|
if array.is_remaining_length():
|
||||||
|
writer.comment("Remaining data must be appended manually").newline()
|
||||||
|
return
|
||||||
|
|
||||||
|
nelements = get_array_size(array, container_src)
|
||||||
|
|
||||||
|
element = "%s__element" % member.name
|
||||||
|
|
||||||
|
if not scope.variable_defined(element):
|
||||||
|
if array.has_attr("ptr_array"):
|
||||||
|
type_formart = "%s * const *"
|
||||||
|
else:
|
||||||
|
type_formart = "const %s * "
|
||||||
|
scope.variable_def(type_formart % element_type.c_type(), element)
|
||||||
|
element_array = element
|
||||||
|
if array.has_attr("ptr_array"):
|
||||||
|
element = "*" + element
|
||||||
|
|
||||||
|
writer.assign(element_array, container_src.get_ref(member.name))
|
||||||
|
|
||||||
|
with writer.index() as index:
|
||||||
|
with writer.for_loop(index, nelements) as array_scope:
|
||||||
|
if element_type.is_primitive():
|
||||||
|
writer.statement("spice_marshaller_add_%s(m, *%s)" % (element_type.primitive_type(), element))
|
||||||
|
elif element_type.is_struct():
|
||||||
|
src2 = RootMarshallingSource(container_src, element_type.c_type(), element_type.sizeof(), element)
|
||||||
|
src2.reuse_scope = array_scope
|
||||||
|
write_container_marshaller(writer, element_type, src2)
|
||||||
|
else:
|
||||||
|
writer.todo("array element unhandled type").newline()
|
||||||
|
|
||||||
|
writer.statement("%s++" % element_array)
|
||||||
|
|
||||||
|
def write_pointer_marshaller(writer, member, src):
|
||||||
|
t = member.member_type
|
||||||
|
ptr_func = write_marshal_ptr_function(writer, t.target_type)
|
||||||
|
submarshaller = "spice_marshaller_get_ptr_submarshaller(m)"
|
||||||
|
if member.has_attr("marshall"):
|
||||||
|
rest_args = ""
|
||||||
|
if t.target_type.is_array():
|
||||||
|
rest_args = ", %s" % get_array_size(t.target_type, src)
|
||||||
|
writer.assign("m2", submarshaller)
|
||||||
|
if t.has_attr("nonnull"):
|
||||||
|
writer.statement("%s(m2, %s%s)" % (ptr_func, src.get_ref(member.name), rest_args))
|
||||||
|
else:
|
||||||
|
with writer.if_block("%s != NULL" % src.get_ref(member.name)) as block:
|
||||||
|
writer.statement("%s(m2, %s%s)" % (ptr_func, src.get_ref(member.name), rest_args))
|
||||||
|
else:
|
||||||
|
writer.assign("*%s_out" % (writer.out_prefix + member.name), submarshaller)
|
||||||
|
|
||||||
|
def write_switch_marshaller(writer, container, switch, src, scope):
|
||||||
|
var = container.lookup_member(switch.variable)
|
||||||
|
var_type = var.member_type
|
||||||
|
|
||||||
|
saved_out_prefix = writer.out_prefix
|
||||||
|
first = True
|
||||||
|
for c in switch.cases:
|
||||||
|
check = c.get_check(src.get_ref(switch.variable), var_type)
|
||||||
|
m = c.member
|
||||||
|
writer.out_prefix = saved_out_prefix
|
||||||
|
if m.has_attr("outvar"):
|
||||||
|
writer.out_prefix = "%s_%s" % (m.attributes["outvar"][0], writer.out_prefix)
|
||||||
|
with writer.if_block(check, not first, False) as block:
|
||||||
|
t = m.member_type
|
||||||
|
if switch.has_attr("anon"):
|
||||||
|
if t.is_struct():
|
||||||
|
src2 = src.child_sub(m)
|
||||||
|
else:
|
||||||
|
src2 = src
|
||||||
|
else:
|
||||||
|
if t.is_struct():
|
||||||
|
src2 = src.child_sub(switch).child_sub(m)
|
||||||
|
else:
|
||||||
|
src2 = src.child_sub(switch)
|
||||||
|
src2.reuse_scope = block
|
||||||
|
|
||||||
|
if t.is_struct():
|
||||||
|
write_container_marshaller(writer, t, src2)
|
||||||
|
elif t.is_pointer():
|
||||||
|
write_pointer_marshaller(writer, m, src2)
|
||||||
|
elif t.is_primitive():
|
||||||
|
if m.has_attr("zero"):
|
||||||
|
writer.statement("spice_marshaller_add_%s(m, 0)" % (t.primitive_type()))
|
||||||
|
else:
|
||||||
|
writer.statement("spice_marshaller_add_%s(m, %s)" % (t.primitive_type(), src2.get_ref(m.name)))
|
||||||
|
#TODO validate e.g. flags and enums
|
||||||
|
elif t.is_array():
|
||||||
|
write_array_marshaller(writer, m, t, src2, scope)
|
||||||
|
else:
|
||||||
|
writer.todo("Can't handle type %s" % m.member_type)
|
||||||
|
|
||||||
|
first = False
|
||||||
|
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
def write_member_marshaller(writer, container, member, src, scope):
|
||||||
|
if member.has_attr("outvar"):
|
||||||
|
writer.out_prefix = "%s_%s" % (member.attributes["outvar"][0], writer.out_prefix)
|
||||||
|
if member.has_attr("virtual"):
|
||||||
|
writer.comment("Don't marshall @virtual %s" % member.name).newline()
|
||||||
|
return
|
||||||
|
if member.has_attr("nomarshal"):
|
||||||
|
writer.comment("Don't marshall @nomarshal %s" % member.name).newline()
|
||||||
|
return
|
||||||
|
if member.is_switch():
|
||||||
|
write_switch_marshaller(writer, container, member, src, scope)
|
||||||
|
return
|
||||||
|
|
||||||
|
t = member.member_type
|
||||||
|
|
||||||
|
if t.is_pointer():
|
||||||
|
write_pointer_marshaller(writer, member, src)
|
||||||
|
elif t.is_primitive():
|
||||||
|
if member.has_attr("zero"):
|
||||||
|
writer.statement("spice_marshaller_add_%s(m, 0)" % (t.primitive_type()))
|
||||||
|
|
||||||
|
else:
|
||||||
|
writer.statement("spice_marshaller_add_%s(m, %s)" % (t.primitive_type(), src.get_ref(member.name)))
|
||||||
|
elif t.is_array():
|
||||||
|
write_array_marshaller(writer, member, t, src, scope)
|
||||||
|
elif t.is_struct():
|
||||||
|
src2 = src.child_sub(member)
|
||||||
|
writer.comment(member.name)
|
||||||
|
write_container_marshaller(writer, t, src2)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError("TODO can't handle parsing of %s" % t)
|
||||||
|
|
||||||
|
def write_container_marshaller(writer, container, src):
|
||||||
|
saved_out_prefix = writer.out_prefix
|
||||||
|
with src.declare(writer) as scope:
|
||||||
|
for m in container.members:
|
||||||
|
writer.out_prefix = saved_out_prefix
|
||||||
|
write_member_marshaller(writer, container, m, src, scope)
|
||||||
|
|
||||||
|
def write_message_marshaller(writer, message, private):
|
||||||
|
if message.has_attr("ifdef"):
|
||||||
|
writer.ifdef(message.attributes["ifdef"][0])
|
||||||
|
writer.header.ifdef(message.attributes["ifdef"][0])
|
||||||
|
writer.out_prefix = ""
|
||||||
|
function_name = "spice_marshall_" + message.c_name()
|
||||||
|
if writer.is_generated("marshaller", function_name):
|
||||||
|
return function_name
|
||||||
|
writer.set_is_generated("marshaller", function_name)
|
||||||
|
|
||||||
|
names = message.get_pointer_names(False)
|
||||||
|
names_args = ""
|
||||||
|
if len(names) > 0:
|
||||||
|
n = [", SpiceMarshaller **%s_out" % name for name in names]
|
||||||
|
names_args = "".join(n)
|
||||||
|
|
||||||
|
if private:
|
||||||
|
message_name = message.c_name()
|
||||||
|
if (not message_name.startswith("msgc_")):
|
||||||
|
#small bug above, checks for startswith("msg") which
|
||||||
|
#matches "msgc" and appends "msg_" if this fails causing
|
||||||
|
#inconsistencies
|
||||||
|
message_name = "msg_" + message_name
|
||||||
|
writer.header.writeln("void (*" + message_name + ")(SpiceMarshaller *m, const %s *msg" % message.c_type() + names_args + ");")
|
||||||
|
else:
|
||||||
|
writer.header.writeln("void " + function_name + "(SpiceMarshaller *m, const %s *msg" % message.c_type() + names_args + ");")
|
||||||
|
|
||||||
|
scope = writer.function(function_name,
|
||||||
|
"static void" if private else "void",
|
||||||
|
"SPICE_GNUC_UNUSED SpiceMarshaller *m, SPICE_GNUC_UNUSED const %s *msg" % message.c_type() + names_args)
|
||||||
|
scope.variable_def("SPICE_GNUC_UNUSED SpiceMarshaller *", "m2")
|
||||||
|
|
||||||
|
for n in names:
|
||||||
|
writer.assign("*%s_out" % n, "NULL")
|
||||||
|
|
||||||
|
# fix warnings about unused variables by not creating body if no members to parse
|
||||||
|
if any(x.is_fixed_nw_size() for x in message.members):
|
||||||
|
src = RootMarshallingSource(None, message.c_type(), message.sizeof(), "msg")
|
||||||
|
src.reuse_scope = scope
|
||||||
|
|
||||||
|
write_container_marshaller(writer, message, src)
|
||||||
|
|
||||||
|
writer.end_block()
|
||||||
|
if message.has_attr("ifdef"):
|
||||||
|
writer.endif(message.attributes["ifdef"][0])
|
||||||
|
writer.header.endif(message.attributes["ifdef"][0])
|
||||||
|
|
||||||
|
writer.newline()
|
||||||
|
return function_name
|
||||||
|
|
||||||
|
def write_protocol_marshaller(writer, proto, is_server, private_marshallers):
|
||||||
|
functions = {}
|
||||||
|
if private_marshallers:
|
||||||
|
writer.header.begin_block("typedef struct")
|
||||||
|
for c in proto.channels:
|
||||||
|
channel = c.channel_type
|
||||||
|
if channel.has_attr("ifdef"):
|
||||||
|
writer.ifdef(channel.attributes["ifdef"][0])
|
||||||
|
writer.header.ifdef(channel.attributes["ifdef"][0])
|
||||||
|
if is_server:
|
||||||
|
messages = channel.client_messages
|
||||||
|
else:
|
||||||
|
messages = channel.server_messages
|
||||||
|
for m in messages:
|
||||||
|
message = m.message_type
|
||||||
|
f = write_message_marshaller(writer, message, private_marshallers)
|
||||||
|
if channel.has_attr("ifdef") and f not in functions:
|
||||||
|
functions[f] = channel.attributes["ifdef"][0]
|
||||||
|
elif message.has_attr("ifdef") and f not in functions:
|
||||||
|
functions[f] = message.attributes["ifdef"][0]
|
||||||
|
else:
|
||||||
|
functions[f] = True
|
||||||
|
if channel.has_attr("ifdef"):
|
||||||
|
writer.endif(channel.attributes["ifdef"][0])
|
||||||
|
writer.header.endif(channel.attributes["ifdef"][0])
|
||||||
|
|
||||||
|
if private_marshallers:
|
||||||
|
writer.header.end_block(newline=False)
|
||||||
|
writer.header.writeln(" SpiceMessageMarshallers;")
|
||||||
|
writer.header.newline()
|
||||||
|
writer.header.statement("SpiceMessageMarshallers *spice_message_marshallers_get" + writer.public_suffix+"(void)")
|
||||||
|
writer.header.newline()
|
||||||
|
|
||||||
|
scope = writer.function("spice_message_marshallers_get" + writer.public_suffix,
|
||||||
|
"SpiceMessageMarshallers *",
|
||||||
|
"void")
|
||||||
|
writer.writeln("static SpiceMessageMarshallers marshallers = {0};").newline()
|
||||||
|
for f in sorted(functions.keys()):
|
||||||
|
member = f[len("spice_marshall_"):]
|
||||||
|
if not member.startswith("msg"):
|
||||||
|
member = "msg_" + member
|
||||||
|
if functions[f] != True:
|
||||||
|
writer.ifdef(functions[f])
|
||||||
|
writer.assign("marshallers.%s" % member, f)
|
||||||
|
if functions[f] != True:
|
||||||
|
writer.endif(functions[f])
|
||||||
|
|
||||||
|
writer.newline()
|
||||||
|
writer.statement("return &marshallers")
|
||||||
|
writer.end_block()
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
def write_trailer(writer):
|
||||||
|
writer.header.newline()
|
||||||
|
writer.header.writeln("SPICE_END_DECLS")
|
||||||
|
writer.header.newline()
|
||||||
|
|
||||||
|
writer.header.writeln("#endif")
|
||||||
6
python_modules/meson.build
Normal file
6
python_modules/meson.build
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
spice_codegen_files += files('codegen.py',
|
||||||
|
'demarshal.py',
|
||||||
|
'__init__.py',
|
||||||
|
'marshal.py',
|
||||||
|
'ptypes.py',
|
||||||
|
'spice_parser.py')
|
||||||
1191
python_modules/ptypes.py
Normal file
1191
python_modules/ptypes.py
Normal file
File diff suppressed because it is too large
Load Diff
159
python_modules/spice_parser.py
Normal file
159
python_modules/spice_parser.py
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
try:
|
||||||
|
from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \
|
||||||
|
Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \
|
||||||
|
alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith
|
||||||
|
except ImportError:
|
||||||
|
print("Module pyparsing not found.")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
from . import ptypes
|
||||||
|
import sys
|
||||||
|
|
||||||
|
cvtInt = lambda toks: int(toks[0])
|
||||||
|
|
||||||
|
def parseVariableDef(toks):
|
||||||
|
t = toks[0][0]
|
||||||
|
pointer = toks[0][1]
|
||||||
|
name = toks[0][2]
|
||||||
|
array_size = toks[0][3]
|
||||||
|
attributes = toks[0][4]
|
||||||
|
|
||||||
|
if array_size != None:
|
||||||
|
t = ptypes.ArrayType(t, array_size)
|
||||||
|
|
||||||
|
if pointer != None:
|
||||||
|
t = ptypes.PointerType(t)
|
||||||
|
|
||||||
|
return ptypes.Member(name, t, attributes)
|
||||||
|
|
||||||
|
bnf = None
|
||||||
|
def SPICE_BNF():
|
||||||
|
global bnf
|
||||||
|
|
||||||
|
if not bnf:
|
||||||
|
|
||||||
|
# punctuation
|
||||||
|
colon = Literal(":").suppress()
|
||||||
|
lbrace = Literal("{").suppress()
|
||||||
|
rbrace = Literal("}").suppress()
|
||||||
|
lbrack = Literal("[").suppress()
|
||||||
|
rbrack = Literal("]").suppress()
|
||||||
|
lparen = Literal("(").suppress()
|
||||||
|
rparen = Literal(")").suppress()
|
||||||
|
equals = Literal("=").suppress()
|
||||||
|
comma = Literal(",").suppress()
|
||||||
|
semi = Literal(";").suppress()
|
||||||
|
|
||||||
|
# primitive types
|
||||||
|
int8_ = Keyword("int8").setParseAction(replaceWith(ptypes.int8))
|
||||||
|
uint8_ = Keyword("uint8").setParseAction(replaceWith(ptypes.uint8))
|
||||||
|
int16_ = Keyword("int16").setParseAction(replaceWith(ptypes.int16))
|
||||||
|
uint16_ = Keyword("uint16").setParseAction(replaceWith(ptypes.uint16))
|
||||||
|
int32_ = Keyword("int32").setParseAction(replaceWith(ptypes.int32))
|
||||||
|
uint32_ = Keyword("uint32").setParseAction(replaceWith(ptypes.uint32))
|
||||||
|
int64_ = Keyword("int64").setParseAction(replaceWith(ptypes.int64))
|
||||||
|
uint64_ = Keyword("uint64").setParseAction(replaceWith(ptypes.uint64))
|
||||||
|
unix_fd_ = Keyword("unix_fd").setParseAction(replaceWith(ptypes.unix_fd))
|
||||||
|
|
||||||
|
# keywords
|
||||||
|
enum32_ = Keyword("enum32").setParseAction(replaceWith(32))
|
||||||
|
enum16_ = Keyword("enum16").setParseAction(replaceWith(16))
|
||||||
|
enum8_ = Keyword("enum8").setParseAction(replaceWith(8))
|
||||||
|
flags32_ = Keyword("flags32").setParseAction(replaceWith(32))
|
||||||
|
flags16_ = Keyword("flags16").setParseAction(replaceWith(16))
|
||||||
|
flags8_ = Keyword("flags8").setParseAction(replaceWith(8))
|
||||||
|
channel_ = Keyword("channel")
|
||||||
|
server_ = Keyword("server")
|
||||||
|
client_ = Keyword("client")
|
||||||
|
protocol_ = Keyword("protocol")
|
||||||
|
typedef_ = Keyword("typedef")
|
||||||
|
struct_ = Keyword("struct")
|
||||||
|
message_ = Keyword("message")
|
||||||
|
image_size_ = Keyword("image_size")
|
||||||
|
cstring_ = Keyword("cstring")
|
||||||
|
switch_ = Keyword("switch")
|
||||||
|
default_ = Keyword("default")
|
||||||
|
case_ = Keyword("case")
|
||||||
|
|
||||||
|
identifier = Word( alphas, alphanums + "_" )
|
||||||
|
enumname = Word( alphanums + "_" )
|
||||||
|
|
||||||
|
integer = ( Combine( CaselessLiteral("0x") + Word( nums+"abcdefABCDEF" ) ) |
|
||||||
|
Word( nums+"+-", nums ) ).setName("int").setParseAction(cvtInt)
|
||||||
|
|
||||||
|
typename = identifier.copy().setParseAction(lambda toks : ptypes.TypeRef(str(toks[0])))
|
||||||
|
|
||||||
|
# This is just normal "types", i.e. not channels or messages
|
||||||
|
typeSpec = Forward()
|
||||||
|
|
||||||
|
attributeValue = integer ^ identifier
|
||||||
|
attribute = Group(Combine ("@" + identifier) + Optional(lparen + delimitedList(attributeValue) + rparen))
|
||||||
|
attributes = Group(ZeroOrMore(attribute))
|
||||||
|
arraySizeSpecImage = Group(image_size_ + lparen + integer + comma + identifier + comma + identifier + rparen)
|
||||||
|
arraySizeSpecCString = Group(cstring_ + lparen + rparen)
|
||||||
|
arraySizeSpec = lbrack + Optional(identifier ^ integer ^ arraySizeSpecImage ^ arraySizeSpecCString, default="") + rbrack
|
||||||
|
variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \
|
||||||
|
.setParseAction(parseVariableDef)
|
||||||
|
|
||||||
|
switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | Group(case_.suppress() + Optional("!", default="") + identifier) + colon)) + variableDef) \
|
||||||
|
.setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1]))
|
||||||
|
switchBody = Group(switch_ + lparen + delimitedList(identifier,delim='.', combine=True) + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \
|
||||||
|
.setParseAction(lambda toks: ptypes.Switch(toks[0][1], toks[0][2], toks[0][3], toks[0][4]))
|
||||||
|
messageBody = structBody = Group(lbrace + ZeroOrMore(variableDef | switchBody) + rbrace)
|
||||||
|
structSpec = Group(struct_ + identifier + structBody + attributes).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3]))
|
||||||
|
|
||||||
|
# have to use longest match for type, in case a user-defined type name starts with a keyword type, like "channel_type"
|
||||||
|
typeSpec << ( structSpec ^ int8_ ^ uint8_ ^ int16_ ^ uint16_ ^
|
||||||
|
int32_ ^ uint32_ ^ int64_ ^ uint64_ ^ unix_fd_ ^
|
||||||
|
typename).setName("type")
|
||||||
|
|
||||||
|
flagsBody = enumBody = Group(lbrace + delimitedList(Group (enumname + Optional(equals + integer, default=None) + attributes)) + Optional(comma) + rbrace)
|
||||||
|
|
||||||
|
messageSpec = Group(message_ + messageBody + attributes).setParseAction(lambda toks: ptypes.MessageType(None, toks[0][1], toks[0][2])) | typename
|
||||||
|
|
||||||
|
channelParent = Optional(colon + typename, default=None)
|
||||||
|
channelMessage = Group(messageSpec + identifier + Optional(equals + integer, default=None) + semi) \
|
||||||
|
.setParseAction(lambda toks: ptypes.ChannelMember(toks[0][1], toks[0][0], toks[0][2]))
|
||||||
|
channelBody = channelParent + Group(lbrace + ZeroOrMore( server_ + colon | client_ + colon | channelMessage) + rbrace)
|
||||||
|
|
||||||
|
enum_ = (enum32_ | enum16_ | enum8_)
|
||||||
|
flags_ = (flags32_ | flags16_ | flags8_)
|
||||||
|
enumDef = Group(enum_ + identifier + enumBody + attributes - semi).setParseAction(lambda toks: ptypes.EnumType(toks[0][0], toks[0][1], toks[0][2], toks[0][3]))
|
||||||
|
flagsDef = Group(flags_ + identifier + flagsBody + attributes - semi).setParseAction(lambda toks: ptypes.FlagsType(toks[0][0], toks[0][1], toks[0][2], toks[0][3]))
|
||||||
|
messageDef = Group(message_ + identifier + messageBody + attributes - semi).setParseAction(lambda toks: ptypes.MessageType(toks[0][1], toks[0][2], toks[0][3]))
|
||||||
|
channelDef = Group(channel_ + identifier + channelBody + attributes - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3], toks[0][4]))
|
||||||
|
structDef = Group(struct_ + identifier + structBody + attributes - semi).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3]))
|
||||||
|
typedefDef = Group(typedef_ + identifier + typeSpec + attributes - semi).setParseAction(lambda toks: ptypes.TypeAlias(toks[0][1], toks[0][2], toks[0][3]))
|
||||||
|
|
||||||
|
definitions = typedefDef | structDef | enumDef | flagsDef | messageDef | channelDef
|
||||||
|
|
||||||
|
protocolChannel = Group(typename + identifier + Optional(equals + integer, default=None) + semi) \
|
||||||
|
.setParseAction(lambda toks: ptypes.ProtocolMember(toks[0][1], toks[0][0], toks[0][2]))
|
||||||
|
protocolDef = Group(protocol_ + identifier + Group(lbrace + ZeroOrMore(protocolChannel) + rbrace) + semi) \
|
||||||
|
.setParseAction(lambda toks: ptypes.ProtocolType(toks[0][1], toks[0][2]))
|
||||||
|
|
||||||
|
bnf = ZeroOrMore (definitions) + protocolDef + StringEnd()
|
||||||
|
|
||||||
|
singleLineComment = "//" + restOfLine
|
||||||
|
bnf.ignore( singleLineComment )
|
||||||
|
bnf.ignore( cStyleComment )
|
||||||
|
|
||||||
|
return bnf
|
||||||
|
|
||||||
|
|
||||||
|
def parse(filename):
|
||||||
|
try:
|
||||||
|
bnf = SPICE_BNF()
|
||||||
|
types = bnf.parseFile(filename)
|
||||||
|
except ParseException as err:
|
||||||
|
print(err.line, file=sys.stderr)
|
||||||
|
print(" "*(err.column-1) + "^", file=sys.stderr)
|
||||||
|
print(err, file=sys.stderr)
|
||||||
|
return None
|
||||||
|
|
||||||
|
for t in types:
|
||||||
|
t.resolve()
|
||||||
|
t.register()
|
||||||
|
protocol = types[-1]
|
||||||
|
return protocol
|
||||||
765
quic_rgb_tmpl.c
765
quic_rgb_tmpl.c
@ -1,765 +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/>.
|
|
||||||
*/
|
|
||||||
#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
|
|
||||||
635
quic_tmpl.c
635
quic_tmpl.c
@ -1,635 +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/>.
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ONE_BYTE
|
|
||||||
#undef ONE_BYTE
|
|
||||||
#define FNAME(name) quic_one_##name
|
|
||||||
#define PIXEL one_byte_t
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef THREE_BYTE
|
|
||||||
#undef THREE_BYTE
|
|
||||||
#define FNAME(name) quic_three_##name
|
|
||||||
#define PIXEL three_bytes_t
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FOUR_BYTE
|
|
||||||
#undef FOUR_BYTE
|
|
||||||
#define FNAME(name) quic_four_##name
|
|
||||||
#define PIXEL four_bytes_t
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#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 _PIXEL_A ((unsigned int)curr[-1].a)
|
|
||||||
#define _PIXEL_B ((unsigned int)prev[0].a)
|
|
||||||
#define _PIXEL_C ((unsigned int)prev[-1].a)
|
|
||||||
|
|
||||||
#ifdef RLE_PRED_1
|
|
||||||
#define RLE_PRED_1_IMP \
|
|
||||||
if (cur_row[i - 1].a == prev_row[i].a) { \
|
|
||||||
if (run_index != i && prev_row[i - 1].a == prev_row[i].a && \
|
|
||||||
i + 1 < end && prev_row[i].a == prev_row[i + 1].a) { \
|
|
||||||
goto do_run; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define RLE_PRED_1_IMP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RLE_PRED_2
|
|
||||||
#define RLE_PRED_2_IMP \
|
|
||||||
if (prev_row[i - 1].a == prev_row[i].a) { \
|
|
||||||
if (run_index != i && i > 2 && cur_row[i - 1].a == cur_row[i - 2].a) { \
|
|
||||||
goto do_run; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define RLE_PRED_2_IMP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RLE_PRED_3
|
|
||||||
#define RLE_PRED_3_IMP \
|
|
||||||
if (i > 1 && cur_row[i - 1].a == cur_row[i - 2].a && i != run_index) { \
|
|
||||||
goto do_run; \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define RLE_PRED_3_IMP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* a */
|
|
||||||
static INLINE BYTE FNAME(decorelate_0)(const PIXEL * const curr, const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
return family.xlatU2L[(unsigned)((int)curr[0].a - (int)_PIXEL_A) & bpc_mask];
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE void FNAME(corelate_0)(PIXEL *curr, const BYTE corelate,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
curr->a = (family.xlatL2U[corelate] + _PIXEL_A) & bpc_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PRED_1
|
|
||||||
|
|
||||||
/* (a+b)/2 */
|
|
||||||
static INLINE BYTE FNAME(decorelate)(const PIXEL *const prev, const PIXEL * const curr,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
return family.xlatU2L[(unsigned)((int)curr->a - (int)((_PIXEL_A + _PIXEL_B) >> 1)) & bpc_mask];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static INLINE void FNAME(corelate)(const PIXEL *prev, PIXEL *curr, const BYTE corelate,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
curr->a = (family.xlatL2U[corelate] + (int)((_PIXEL_A + _PIXEL_B) >> 1)) & bpc_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PRED_2
|
|
||||||
|
|
||||||
/* .75a+.75b-.5c */
|
|
||||||
static INLINE BYTE FNAME(decorelate)(const PIXEL *const prev, const PIXEL * const curr,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
int p = ((int)(3 * (_PIXEL_A + _PIXEL_B)) - (int)(_PIXEL_C << 1)) >> 2;
|
|
||||||
|
|
||||||
if (p < 0) {
|
|
||||||
p = 0;
|
|
||||||
} else if ((unsigned)p > bpc_mask) {
|
|
||||||
p = bpc_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
return family.xlatU2L[(unsigned)((int)curr->a - p) & bpc_mask];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE void FNAME(corelate)(const PIXEL *prev, PIXEL *curr, const BYTE corelate,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
const int p = ((int)(3 * (_PIXEL_A + _PIXEL_B)) - (int)(_PIXEL_C << 1)) >> 2;
|
|
||||||
const unsigned int s = family.xlatL2U[corelate];
|
|
||||||
|
|
||||||
if (!(p & ~bpc_mask)) {
|
|
||||||
curr->a = (s + (unsigned)p) & bpc_mask;
|
|
||||||
} else if (p < 0) {
|
|
||||||
curr->a = s;
|
|
||||||
} else {
|
|
||||||
curr->a = (s + bpc_mask) & bpc_mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void FNAME(compress_row0_seg)(Encoder *encoder, Channel *channel, int i,
|
|
||||||
const PIXEL * const cur_row,
|
|
||||||
const int end,
|
|
||||||
const unsigned int waitmask,
|
|
||||||
const unsigned int bpc,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
BYTE * const decorelate_drow = channel->correlate_row;
|
|
||||||
int stopidx;
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, end - i > 0);
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
|
|
||||||
decorelate_drow[0] = family.xlatU2L[cur_row->a];
|
|
||||||
golomb_coding(decorelate_drow[0], find_bucket(channel, decorelate_drow[-1])->bestcode,
|
|
||||||
&codeword, &codewordlen);
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
|
|
||||||
if (channel->state.waitcnt) {
|
|
||||||
channel->state.waitcnt--;
|
|
||||||
} else {
|
|
||||||
channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
|
|
||||||
update_model(&channel->state, find_bucket(channel, decorelate_drow[-1]),
|
|
||||||
decorelate_drow[i], bpc);
|
|
||||||
}
|
|
||||||
stopidx = ++i + channel->state.waitcnt;
|
|
||||||
} else {
|
|
||||||
stopidx = i + channel->state.waitcnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (stopidx < end) {
|
|
||||||
for (; i <= stopidx; i++) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
decorelate_drow[i] = FNAME(decorelate_0)(&cur_row[i], bpc_mask);
|
|
||||||
golomb_coding(decorelate_drow[i],
|
|
||||||
find_bucket(channel, decorelate_drow[i - 1])->bestcode, &codeword,
|
|
||||||
&codewordlen);
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
update_model(&channel->state, find_bucket(channel, decorelate_drow[stopidx - 1]),
|
|
||||||
decorelate_drow[stopidx], bpc);
|
|
||||||
stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < end; i++) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
decorelate_drow[i] = FNAME(decorelate_0)(&cur_row[i], bpc_mask);
|
|
||||||
golomb_coding(decorelate_drow[i], find_bucket(channel, decorelate_drow[i - 1])->bestcode,
|
|
||||||
&codeword, &codewordlen);
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
}
|
|
||||||
channel->state.waitcnt = stopidx - end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(compress_row0)(Encoder *encoder, Channel *channel, 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)channel->state.wmidx) && (channel->state.wmileft <= width)) {
|
|
||||||
if (channel->state.wmileft) {
|
|
||||||
FNAME(compress_row0_seg)(encoder, channel, pos, cur_row, pos + channel->state.wmileft,
|
|
||||||
bppmask[channel->state.wmidx], bpc, bpc_mask);
|
|
||||||
width -= channel->state.wmileft;
|
|
||||||
pos += channel->state.wmileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
channel->state.wmidx++;
|
|
||||||
set_wm_trigger(&channel->state);
|
|
||||||
channel->state.wmileft = wminext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width) {
|
|
||||||
FNAME(compress_row0_seg)(encoder, channel, pos, cur_row, pos + width,
|
|
||||||
bppmask[channel->state.wmidx], bpc, bpc_mask);
|
|
||||||
if (wmimax > (int)channel->state.wmidx) {
|
|
||||||
channel->state.wmileft -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
|
|
||||||
ASSERT(encoder->usr, channel->state.wmidx <= 32);
|
|
||||||
ASSERT(encoder->usr, wminext > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(compress_row_seg)(Encoder *encoder, Channel *channel, 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)
|
|
||||||
{
|
|
||||||
BYTE * const decorelate_drow = channel->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;
|
|
||||||
|
|
||||||
decorelate_drow[0] = family.xlatU2L[(unsigned)((int)cur_row->a -
|
|
||||||
(int)prev_row->a) & bpc_mask];
|
|
||||||
|
|
||||||
golomb_coding(decorelate_drow[0],
|
|
||||||
find_bucket(channel, decorelate_drow[-1])->bestcode,
|
|
||||||
&codeword,
|
|
||||||
&codewordlen);
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
|
|
||||||
if (channel->state.waitcnt) {
|
|
||||||
channel->state.waitcnt--;
|
|
||||||
} else {
|
|
||||||
channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
|
|
||||||
update_model(&channel->state, find_bucket(channel, decorelate_drow[-1]),
|
|
||||||
decorelate_drow[0], bpc);
|
|
||||||
}
|
|
||||||
stopidx = ++i + channel->state.waitcnt;
|
|
||||||
} else {
|
|
||||||
stopidx = i + channel->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
|
|
||||||
decorelate_drow[i] = FNAME(decorelate)(&prev_row[i], &cur_row[i], bpc_mask);
|
|
||||||
golomb_coding(decorelate_drow[i],
|
|
||||||
find_bucket(channel, decorelate_drow[i - 1])->bestcode, &codeword,
|
|
||||||
&codewordlen);
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
update_model(&channel->state, find_bucket(channel, decorelate_drow[stopidx - 1]),
|
|
||||||
decorelate_drow[stopidx], bpc);
|
|
||||||
stopidx = i + (tabrand(&channel->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
|
|
||||||
decorelate_drow[i] = FNAME(decorelate)(&prev_row[i], &cur_row[i], bpc_mask);
|
|
||||||
golomb_coding(decorelate_drow[i], find_bucket(channel,
|
|
||||||
decorelate_drow[i - 1])->bestcode,
|
|
||||||
&codeword, &codewordlen);
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
}
|
|
||||||
channel->state.waitcnt = stopidx - end;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef RLE
|
|
||||||
do_run:
|
|
||||||
run_index = i;
|
|
||||||
channel->state.waitcnt = stopidx - i;
|
|
||||||
run_size = 0;
|
|
||||||
|
|
||||||
while (cur_row[i].a == cur_row[i - 1].a) {
|
|
||||||
run_size++;
|
|
||||||
if (++i == end) {
|
|
||||||
#ifdef RLE_STAT
|
|
||||||
encode_channel_run(encoder, channel, run_size);
|
|
||||||
#else
|
|
||||||
encode_run(encoder, run_size);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef RLE_STAT
|
|
||||||
encode_channel_run(encoder, channel, run_size);
|
|
||||||
#else
|
|
||||||
encode_run(encoder, run_size);
|
|
||||||
#endif
|
|
||||||
stopidx = i + channel->state.waitcnt;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(compress_row)(Encoder *encoder, Channel *channel,
|
|
||||||
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)channel->state.wmidx) && (channel->state.wmileft <= width)) {
|
|
||||||
if (channel->state.wmileft) {
|
|
||||||
FNAME(compress_row_seg)(encoder, channel, pos, prev_row, cur_row,
|
|
||||||
pos + channel->state.wmileft, bppmask[channel->state.wmidx],
|
|
||||||
bpc, bpc_mask);
|
|
||||||
width -= channel->state.wmileft;
|
|
||||||
pos += channel->state.wmileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
channel->state.wmidx++;
|
|
||||||
set_wm_trigger(&channel->state);
|
|
||||||
channel->state.wmileft = wminext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width) {
|
|
||||||
FNAME(compress_row_seg)(encoder, channel, pos, prev_row, cur_row, pos + width,
|
|
||||||
bppmask[channel->state.wmidx], bpc, bpc_mask);
|
|
||||||
if (wmimax > (int)channel->state.wmidx) {
|
|
||||||
channel->state.wmileft -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
|
|
||||||
ASSERT(encoder->usr, channel->state.wmidx <= 32);
|
|
||||||
ASSERT(encoder->usr, wminext > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(uncompress_row0_seg)(Encoder *encoder, Channel *channel, int i,
|
|
||||||
BYTE * const correlate_row,
|
|
||||||
PIXEL * const cur_row,
|
|
||||||
const int end,
|
|
||||||
const unsigned int waitmask,
|
|
||||||
const unsigned int bpc,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
int stopidx;
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, end - i > 0);
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
|
|
||||||
correlate_row[0] = (BYTE)golomb_decoding(find_bucket(channel,
|
|
||||||
correlate_row[-1])->bestcode,
|
|
||||||
encoder->io_word, &codewordlen);
|
|
||||||
cur_row[0].a = (BYTE)family.xlatL2U[correlate_row[0]];
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
|
|
||||||
if (channel->state.waitcnt) {
|
|
||||||
--channel->state.waitcnt;
|
|
||||||
} else {
|
|
||||||
channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
|
|
||||||
update_model(&channel->state, find_bucket(channel, correlate_row[-1]),
|
|
||||||
correlate_row[0], bpc);
|
|
||||||
}
|
|
||||||
stopidx = ++i + channel->state.waitcnt;
|
|
||||||
} else {
|
|
||||||
stopidx = i + channel->state.waitcnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (stopidx < end) {
|
|
||||||
struct s_bucket * pbucket = NULL;
|
|
||||||
|
|
||||||
for (; i <= stopidx; i++) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
|
|
||||||
pbucket = find_bucket(channel, correlate_row[i - 1]);
|
|
||||||
correlate_row[i] = (BYTE)golomb_decoding(pbucket->bestcode, encoder->io_word,
|
|
||||||
&codewordlen);
|
|
||||||
FNAME(corelate_0)(&cur_row[i], correlate_row[i], bpc_mask);
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
update_model(&channel->state, pbucket, correlate_row[stopidx], bpc);
|
|
||||||
|
|
||||||
stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < end; i++) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
|
|
||||||
correlate_row[i] = (BYTE)golomb_decoding(find_bucket(channel,
|
|
||||||
correlate_row[i - 1])->bestcode,
|
|
||||||
encoder->io_word, &codewordlen);
|
|
||||||
FNAME(corelate_0)(&cur_row[i], correlate_row[i], bpc_mask);
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
}
|
|
||||||
channel->state.waitcnt = stopidx - end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(uncompress_row0)(Encoder *encoder, Channel *channel,
|
|
||||||
PIXEL * const cur_row,
|
|
||||||
unsigned int width)
|
|
||||||
|
|
||||||
{
|
|
||||||
const unsigned int bpc = BPC;
|
|
||||||
const unsigned int bpc_mask = BPC_MASK;
|
|
||||||
BYTE * const correlate_row = channel->correlate_row;
|
|
||||||
unsigned int pos = 0;
|
|
||||||
|
|
||||||
while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
|
|
||||||
if (channel->state.wmileft) {
|
|
||||||
FNAME(uncompress_row0_seg)(encoder, channel, pos, correlate_row, cur_row,
|
|
||||||
pos + channel->state.wmileft, bppmask[channel->state.wmidx],
|
|
||||||
bpc, bpc_mask);
|
|
||||||
pos += channel->state.wmileft;
|
|
||||||
width -= channel->state.wmileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
channel->state.wmidx++;
|
|
||||||
set_wm_trigger(&channel->state);
|
|
||||||
channel->state.wmileft = wminext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width) {
|
|
||||||
FNAME(uncompress_row0_seg)(encoder, channel, pos, correlate_row, cur_row, pos + width,
|
|
||||||
bppmask[channel->state.wmidx], bpc, bpc_mask);
|
|
||||||
if (wmimax > (int)channel->state.wmidx) {
|
|
||||||
channel->state.wmileft -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
|
|
||||||
ASSERT(encoder->usr, channel->state.wmidx <= 32);
|
|
||||||
ASSERT(encoder->usr, wminext > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(uncompress_row_seg)(Encoder *encoder, Channel *channel,
|
|
||||||
BYTE *correlate_row,
|
|
||||||
const PIXEL * const prev_row,
|
|
||||||
PIXEL * const cur_row,
|
|
||||||
int i,
|
|
||||||
const int end,
|
|
||||||
const unsigned int bpc,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
const unsigned int waitmask = bppmask[channel->state.wmidx];
|
|
||||||
int stopidx;
|
|
||||||
#ifdef RLE
|
|
||||||
int run_index = 0;
|
|
||||||
int run_end;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, end - i > 0);
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
|
|
||||||
correlate_row[0] = (BYTE)golomb_decoding(find_bucket(channel, correlate_row[-1])->bestcode,
|
|
||||||
encoder->io_word, &codewordlen);
|
|
||||||
cur_row[0].a = (family.xlatL2U[correlate_row[0]] + prev_row[0].a) & bpc_mask;
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
|
|
||||||
if (channel->state.waitcnt) {
|
|
||||||
--channel->state.waitcnt;
|
|
||||||
} else {
|
|
||||||
channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
|
|
||||||
update_model(&channel->state, find_bucket(channel, correlate_row[-1]),
|
|
||||||
correlate_row[0], bpc);
|
|
||||||
}
|
|
||||||
stopidx = ++i + channel->state.waitcnt;
|
|
||||||
} else {
|
|
||||||
stopidx = i + channel->state.waitcnt;
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
while (stopidx < end) {
|
|
||||||
struct s_bucket * pbucket = NULL;
|
|
||||||
|
|
||||||
for (; i <= stopidx; i++) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
#ifdef RLE
|
|
||||||
RLE_PRED_1_IMP;
|
|
||||||
RLE_PRED_2_IMP;
|
|
||||||
RLE_PRED_3_IMP;
|
|
||||||
#endif
|
|
||||||
pbucket = find_bucket(channel, correlate_row[i - 1]);
|
|
||||||
correlate_row[i] = (BYTE)golomb_decoding(pbucket->bestcode, encoder->io_word,
|
|
||||||
&codewordlen);
|
|
||||||
FNAME(corelate)(&prev_row[i], &cur_row[i], correlate_row[i], bpc_mask);
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
update_model(&channel->state, pbucket, correlate_row[stopidx], bpc);
|
|
||||||
|
|
||||||
stopidx = i + (tabrand(&channel->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
|
|
||||||
correlate_row[i] = (BYTE)golomb_decoding(find_bucket(channel,
|
|
||||||
correlate_row[i - 1])->bestcode,
|
|
||||||
encoder->io_word, &codewordlen);
|
|
||||||
FNAME(corelate)(&prev_row[i], &cur_row[i], correlate_row[i], bpc_mask);
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
channel->state.waitcnt = stopidx - end;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef RLE
|
|
||||||
do_run:
|
|
||||||
channel->state.waitcnt = stopidx - i;
|
|
||||||
run_index = i;
|
|
||||||
#ifdef RLE_STAT
|
|
||||||
run_end = i + decode_channel_run(encoder, channel);
|
|
||||||
#else
|
|
||||||
run_end = i + decode_run(encoder);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (; i < run_end; i++) {
|
|
||||||
cur_row[i].a = cur_row[i - 1].a;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == end) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stopidx = i + channel->state.waitcnt;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(uncompress_row)(Encoder *encoder, Channel *channel,
|
|
||||||
const PIXEL * const prev_row,
|
|
||||||
PIXEL * const cur_row,
|
|
||||||
unsigned int width)
|
|
||||||
|
|
||||||
{
|
|
||||||
const unsigned int bpc = BPC;
|
|
||||||
const unsigned int bpc_mask = BPC_MASK;
|
|
||||||
BYTE * const correlate_row = channel->correlate_row;
|
|
||||||
unsigned int pos = 0;
|
|
||||||
|
|
||||||
while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
|
|
||||||
if (channel->state.wmileft) {
|
|
||||||
FNAME(uncompress_row_seg)(encoder, channel, correlate_row, prev_row, cur_row, pos,
|
|
||||||
pos + channel->state.wmileft, bpc, bpc_mask);
|
|
||||||
pos += channel->state.wmileft;
|
|
||||||
width -= channel->state.wmileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
channel->state.wmidx++;
|
|
||||||
set_wm_trigger(&channel->state);
|
|
||||||
channel->state.wmileft = wminext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width) {
|
|
||||||
FNAME(uncompress_row_seg)(encoder, channel, correlate_row, prev_row, cur_row, pos,
|
|
||||||
pos + width, bpc, bpc_mask);
|
|
||||||
if (wmimax > (int)channel->state.wmidx) {
|
|
||||||
channel->state.wmileft -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
|
|
||||||
ASSERT(encoder->usr, channel->state.wmidx <= 32);
|
|
||||||
ASSERT(encoder->usr, wminext > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef PIXEL
|
|
||||||
#undef FNAME
|
|
||||||
#undef _PIXEL_A
|
|
||||||
#undef _PIXEL_B
|
|
||||||
#undef _PIXEL_C
|
|
||||||
#undef RLE_PRED_1_IMP
|
|
||||||
#undef RLE_PRED_2_IMP
|
|
||||||
#undef RLE_PRED_3_IMP
|
|
||||||
#undef golomb_coding
|
|
||||||
#undef golomb_deoding
|
|
||||||
#undef update_model
|
|
||||||
#undef find_bucket
|
|
||||||
#undef family
|
|
||||||
#undef BPC
|
|
||||||
#undef BPC_MASK
|
|
||||||
1398
spice.proto
Normal file
1398
spice.proto
Normal file
File diff suppressed because it is too large
Load Diff
366
spice_codegen.py
Executable file
366
spice_codegen.py
Executable file
@ -0,0 +1,366 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from optparse import OptionParser
|
||||||
|
import traceback
|
||||||
|
from python_modules import spice_parser
|
||||||
|
from python_modules import ptypes
|
||||||
|
from python_modules import codegen
|
||||||
|
from python_modules import demarshal
|
||||||
|
from python_modules import marshal
|
||||||
|
|
||||||
|
|
||||||
|
def write_channel_enums(writer, channel, client, describe):
|
||||||
|
messages = list(filter(lambda m : m.channel == channel, \
|
||||||
|
channel.client_messages if client else channel.server_messages))
|
||||||
|
if len(messages) == 0:
|
||||||
|
return
|
||||||
|
if client:
|
||||||
|
prefix = [ "MSGC" ]
|
||||||
|
else:
|
||||||
|
prefix = [ "MSG" ]
|
||||||
|
if channel.member_name:
|
||||||
|
prefix.append(channel.member_name.upper())
|
||||||
|
if not describe:
|
||||||
|
writer.begin_block("enum")
|
||||||
|
else:
|
||||||
|
writer.begin_block("static const value_string %s_vs[] = " % (codegen.prefix_underscore_lower(*[x.lower() for x in prefix])))
|
||||||
|
i = 0
|
||||||
|
prefix.append(None) # To be replaced with name
|
||||||
|
for m in messages:
|
||||||
|
prefix[-1] = m.name.upper()
|
||||||
|
enum = codegen.prefix_underscore_upper(*prefix)
|
||||||
|
if describe:
|
||||||
|
writer.writeln("{ %s, \"%s %s\" }," % (enum, "Client" if client else "Server", m.name.upper()))
|
||||||
|
else:
|
||||||
|
if m.value == i:
|
||||||
|
writer.writeln("%s," % enum)
|
||||||
|
i = i + 1
|
||||||
|
else:
|
||||||
|
writer.writeln("%s = %s," % (enum, m.value))
|
||||||
|
i = m.value + 1
|
||||||
|
if describe:
|
||||||
|
writer.writeln("{ 0, NULL }");
|
||||||
|
else:
|
||||||
|
if channel.member_name:
|
||||||
|
prefix[-1] = prefix[-2]
|
||||||
|
prefix[-2] = "END"
|
||||||
|
writer.newline()
|
||||||
|
writer.writeln("%s" % (codegen.prefix_underscore_upper(*prefix)))
|
||||||
|
writer.end_block(semicolon=True)
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
def write_channel_type_enum(writer, describe=False):
|
||||||
|
i = 0
|
||||||
|
if describe:
|
||||||
|
writer.begin_block("static const value_string channel_types_vs[] =")
|
||||||
|
else:
|
||||||
|
writer.begin_block("enum")
|
||||||
|
for c in proto.channels:
|
||||||
|
enum = codegen.prefix_underscore_upper("CHANNEL", c.name.upper())
|
||||||
|
if describe:
|
||||||
|
writer.writeln("{ %s, \"%s\" }," % (enum, c.name.upper()))
|
||||||
|
else:
|
||||||
|
if c.value == i:
|
||||||
|
writer.writeln("%s," % enum)
|
||||||
|
i = i + 1
|
||||||
|
else:
|
||||||
|
writer.writeln("%s = %s," % (enum, c.value))
|
||||||
|
i = c.value + 1
|
||||||
|
writer.newline()
|
||||||
|
if describe:
|
||||||
|
writer.writeln("{ 0, NULL }")
|
||||||
|
else:
|
||||||
|
writer.writeln("SPICE_END_CHANNEL")
|
||||||
|
writer.end_block(semicolon=True)
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
|
||||||
|
def write_enums(writer, describe=False):
|
||||||
|
writer.writeln("#ifndef _H_SPICE_ENUMS")
|
||||||
|
writer.writeln("#define _H_SPICE_ENUMS")
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
# Define enums
|
||||||
|
for t in ptypes.get_named_types():
|
||||||
|
if isinstance(t, ptypes.EnumBaseType):
|
||||||
|
t.c_define(writer)
|
||||||
|
if describe:
|
||||||
|
t.c_describe(writer)
|
||||||
|
|
||||||
|
write_channel_type_enum(writer)
|
||||||
|
if (describe):
|
||||||
|
write_channel_type_enum(writer, True)
|
||||||
|
|
||||||
|
for c in ptypes.get_named_types():
|
||||||
|
if not isinstance(c, ptypes.ChannelType):
|
||||||
|
continue
|
||||||
|
write_channel_enums(writer, c, False, False)
|
||||||
|
if describe:
|
||||||
|
write_channel_enums(writer, c, False, describe)
|
||||||
|
write_channel_enums(writer, c, True, False)
|
||||||
|
if describe:
|
||||||
|
write_channel_enums(writer, c, True, describe)
|
||||||
|
|
||||||
|
writer.writeln("#endif /* _H_SPICE_ENUMS */")
|
||||||
|
|
||||||
|
def write_content(dest_file, content, keep_identical_file):
|
||||||
|
if keep_identical_file:
|
||||||
|
try:
|
||||||
|
with open(dest_file, 'rb') as f:
|
||||||
|
old_content = f.read()
|
||||||
|
|
||||||
|
if content == old_content:
|
||||||
|
print("No changes to %s" % dest_file)
|
||||||
|
return
|
||||||
|
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with open(dest_file, 'wb') as f:
|
||||||
|
f.write(bytes(content, 'UTF-8'))
|
||||||
|
|
||||||
|
print("Wrote %s" % dest_file)
|
||||||
|
|
||||||
|
|
||||||
|
parser = OptionParser(usage="usage: %prog [options] <protocol_file> <destination file>")
|
||||||
|
parser.add_option("-e", "--generate-enums",
|
||||||
|
action="store_true", dest="generate_enums", default=False,
|
||||||
|
help="Generate enums")
|
||||||
|
parser.add_option("-w", "--generate-wireshark-dissector",
|
||||||
|
action="store_true", dest="generate_dissector", default=False,
|
||||||
|
help="Generate Wireshark dissector definitions")
|
||||||
|
parser.add_option("-d", "--generate-demarshallers",
|
||||||
|
action="store_true", dest="generate_demarshallers", default=False,
|
||||||
|
help="Generate demarshallers")
|
||||||
|
parser.add_option("-m", "--generate-marshallers",
|
||||||
|
action="store_true", dest="generate_marshallers", default=False,
|
||||||
|
help="Generate message marshallers")
|
||||||
|
parser.add_option("-P", "--private-marshallers",
|
||||||
|
action="store_true", dest="private_marshallers", default=False,
|
||||||
|
help="Generate private message marshallers")
|
||||||
|
parser.add_option("-M", "--generate-struct-marshaller",
|
||||||
|
action="append", dest="struct_marshallers",
|
||||||
|
help="Generate struct marshallers")
|
||||||
|
parser.add_option("-a", "--assert-on-error",
|
||||||
|
action="store_true", dest="assert_on_error", default=False,
|
||||||
|
help="Assert on error")
|
||||||
|
parser.add_option("-H", "--header",
|
||||||
|
action="store_true", dest="header", default=False,
|
||||||
|
help="Generate header")
|
||||||
|
parser.add_option("-p", "--print-error",
|
||||||
|
action="store_true", dest="print_error", default=False,
|
||||||
|
help="Print errors")
|
||||||
|
parser.add_option("-s", "--server",
|
||||||
|
action="store_true", dest="server", default=False,
|
||||||
|
help="Print errors")
|
||||||
|
parser.add_option("-c", "--client",
|
||||||
|
action="store_true", dest="client", default=False,
|
||||||
|
help="Print errors")
|
||||||
|
parser.add_option("-k", "--keep-identical-file",
|
||||||
|
action="store_true", dest="keep_identical_file", default=False,
|
||||||
|
help="Print errors")
|
||||||
|
parser.add_option("-i", "--include",
|
||||||
|
action="append", dest="includes", metavar="FILE",
|
||||||
|
help="Include FILE in generated code")
|
||||||
|
parser.add_option("--suffix", dest="suffix",
|
||||||
|
help="set public symbol suffix", default="")
|
||||||
|
parser.add_option("--license", dest="license",
|
||||||
|
help="license to use for generated file(s) (LGPL/BSD)", default="LGPL")
|
||||||
|
parser.add_option("--generate-header",
|
||||||
|
action="store_true", dest="generate_header", default=False,
|
||||||
|
help="Generate also the header")
|
||||||
|
parser.add_option("--generated-declaration-file", dest="generated_declaration_file", metavar="FILE",
|
||||||
|
help="Name of the file to generate declarations")
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
if len(args) == 0:
|
||||||
|
parser.error("No protocol file specified")
|
||||||
|
|
||||||
|
if len(args) == 1:
|
||||||
|
parser.error("No destination file specified")
|
||||||
|
|
||||||
|
proto_file = args[0]
|
||||||
|
dest_file = args[1]
|
||||||
|
proto = spice_parser.parse(proto_file)
|
||||||
|
|
||||||
|
if proto == None:
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
codegen.set_prefix(proto.name)
|
||||||
|
writer = codegen.CodeWriter()
|
||||||
|
writer.header = codegen.CodeWriter()
|
||||||
|
if options.generate_header:
|
||||||
|
filename = os.path.splitext(dest_file)[0] + '.h'
|
||||||
|
writer.header.set_option("dest_file", filename)
|
||||||
|
else:
|
||||||
|
writer.header.set_option("dest_file", dest_file)
|
||||||
|
writer.set_option("source", os.path.basename(proto_file))
|
||||||
|
|
||||||
|
if options.license == "LGPL":
|
||||||
|
license = """/*
|
||||||
|
Copyright (C) 2013 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
"""
|
||||||
|
elif options.license == "BSD":
|
||||||
|
license = """/*
|
||||||
|
Copyright (C) 2013 Red Hat, Inc.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
|
||||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
print("Invalid license specified: %s" % options.license, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
all_structures = {}
|
||||||
|
def generate_declaration(t, writer_top):
|
||||||
|
writer = codegen.CodeWriter()
|
||||||
|
try:
|
||||||
|
c_type = t.c_type()
|
||||||
|
t.generate_c_declaration(writer)
|
||||||
|
value = writer.getvalue().strip()
|
||||||
|
if not value:
|
||||||
|
return
|
||||||
|
if c_type in all_structures:
|
||||||
|
assert all_structures[c_type] == value, """Structure %s redefinition
|
||||||
|
previous:
|
||||||
|
%s
|
||||||
|
---
|
||||||
|
current:
|
||||||
|
%s
|
||||||
|
---""" % (c_type, all_structures[c_type], value)
|
||||||
|
else:
|
||||||
|
all_structures[c_type] = value
|
||||||
|
t.generate_c_declaration(writer_top)
|
||||||
|
except:
|
||||||
|
print('type %s' % t, file=sys.stderr)
|
||||||
|
print(writer.getvalue(), file=sys.stderr)
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def generate_declarations():
|
||||||
|
writer = codegen.CodeWriter()
|
||||||
|
writer.public_suffix = options.suffix
|
||||||
|
writer.write(license)
|
||||||
|
|
||||||
|
# all types
|
||||||
|
for t in ptypes.get_named_types():
|
||||||
|
if isinstance(t, ptypes.StructType):
|
||||||
|
generate_declaration(t, writer)
|
||||||
|
if isinstance(t, ptypes.ChannelType):
|
||||||
|
for m in t.client_messages + t.server_messages:
|
||||||
|
generate_declaration(m.message_type, writer)
|
||||||
|
|
||||||
|
content = writer.getvalue()
|
||||||
|
write_content(options.generated_declaration_file, content,
|
||||||
|
options.keep_identical_file)
|
||||||
|
|
||||||
|
if options.generated_declaration_file:
|
||||||
|
generate_declarations()
|
||||||
|
|
||||||
|
writer.public_suffix = options.suffix
|
||||||
|
|
||||||
|
writer.writeln("/* this is a file autogenerated by spice_codegen.py */")
|
||||||
|
writer.write(license)
|
||||||
|
writer.header.writeln("/* this is a file autogenerated by spice_codegen.py */")
|
||||||
|
writer.header.write(license)
|
||||||
|
if not options.generate_enums:
|
||||||
|
writer.writeln("#include <config.h>")
|
||||||
|
|
||||||
|
if options.assert_on_error:
|
||||||
|
writer.set_option("assert_on_error")
|
||||||
|
|
||||||
|
if options.print_error:
|
||||||
|
writer.set_option("print_error")
|
||||||
|
|
||||||
|
if options.includes:
|
||||||
|
for i in options.includes:
|
||||||
|
writer.header.writeln('#include "%s"' % i)
|
||||||
|
writer.writeln('#include "%s"' % i)
|
||||||
|
|
||||||
|
if options.generate_enums or options.generate_dissector:
|
||||||
|
write_enums(writer, options.generate_dissector)
|
||||||
|
|
||||||
|
if options.generate_demarshallers:
|
||||||
|
if not options.server and not options.client:
|
||||||
|
print("Must specify client and/or server", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
demarshal.write_includes(writer)
|
||||||
|
|
||||||
|
if options.server:
|
||||||
|
demarshal.write_protocol_parser(writer, proto, False)
|
||||||
|
if options.client:
|
||||||
|
demarshal.write_protocol_parser(writer, proto, True)
|
||||||
|
|
||||||
|
if options.generate_marshallers or (options.struct_marshallers and len(options.struct_marshallers) > 0):
|
||||||
|
marshal.write_includes(writer)
|
||||||
|
|
||||||
|
if options.generate_marshallers:
|
||||||
|
if not options.server and not options.client:
|
||||||
|
print("Must specify client and/or server", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
if options.server:
|
||||||
|
marshal.write_protocol_marshaller(writer, proto, False, options.private_marshallers)
|
||||||
|
if options.client:
|
||||||
|
marshal.write_protocol_marshaller(writer, proto, True, options.private_marshallers)
|
||||||
|
|
||||||
|
if options.struct_marshallers:
|
||||||
|
for structname in options.struct_marshallers:
|
||||||
|
t = ptypes.lookup_type(structname)
|
||||||
|
marshal.write_marshal_ptr_function(writer, t, False)
|
||||||
|
|
||||||
|
if options.generate_marshallers or (options.struct_marshallers and len(options.struct_marshallers) > 0):
|
||||||
|
marshal.write_trailer(writer)
|
||||||
|
|
||||||
|
if options.header:
|
||||||
|
content = writer.header.getvalue()
|
||||||
|
else:
|
||||||
|
content = writer.getvalue()
|
||||||
|
write_content(dest_file, content, options.keep_identical_file)
|
||||||
|
if options.generate_header:
|
||||||
|
content = writer.header.getvalue()
|
||||||
|
filename = writer.header.options["dest_file"]
|
||||||
|
write_content(filename, content, options.keep_identical_file)
|
||||||
|
sys.exit(0)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user