esajpip-0.1~bzr33/0000755000175000017500000000000012335423210013734 5ustar mathieumathieuesajpip-0.1~bzr33/doc/0000755000175000017500000000000012335423210014501 5ustar mathieumathieuesajpip-0.1~bzr33/doc/jpip_fig.fig0000644000175000017500000000717012335423210016764 0ustar mathieumathieu#FIG 3.2 Produced by xfig version 3.2.5b Landscape Center Inches Letter 100.00 Single -2 1200 2 0 32 #e7e7e7 0 33 #b6d5ae 0 34 #aeb2d5 1 2 0 1 0 33 56 -1 20 0.000 1 0.0000 1879 6225 521 75 1358 6150 2400 6300 1 2 0 1 0 33 50 -1 30 0.000 1 0.0000 1879 5625 521 75 1358 5625 2400 5625 1 2 2 1 0 33 50 -1 30 3.000 1 0.0000 3079 5625 521 75 2558 5625 3600 5625 1 2 2 1 0 33 56 -1 20 3.000 1 0.0000 3079 6225 521 75 2558 6150 3600 6300 1 2 2 1 0 33 56 -1 20 3.000 1 0.0000 5854 6225 521 75 5333 6150 6375 6300 1 2 2 1 0 33 50 -1 30 3.000 1 0.0000 5854 5625 521 75 5333 5625 6375 5625 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1350 5625 1350 6225 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2400 5625 2400 6225 2 2 0 0 0 33 55 -1 20 0.000 0 0 7 0 0 5 1350 5625 2400 5625 2400 6225 1350 6225 1350 5625 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 3075 5175 3075 5625 2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 7350 4875 6375 4875 2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6375 5025 7350 5025 2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 7800 5175 7800 5700 2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 7950 5700 7950 5175 2 1 0 1 0 7 50 -1 -1 0.000 0 0 7 0 1 2 1 1 1.00 60.00 120.00 3675 4875 5325 4875 2 1 0 1 0 7 50 -1 -1 0.000 0 0 7 0 1 2 1 1 1.00 60.00 120.00 5325 5025 3675 5025 2 1 0 1 0 32 50 -1 31 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6375 5925 7350 5925 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3600 5625 3600 6225 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 2550 5625 2550 6225 2 2 2 0 0 33 55 -1 20 3.000 0 0 7 0 0 5 2550 5625 3600 5625 3600 6225 2550 6225 2550 5625 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 5850 5175 5850 5625 2 2 2 1 0 7 70 -1 -1 3.000 0 0 7 0 0 5 1200 4200 3900 4200 3900 6450 1200 6450 1200 4200 2 2 2 1 0 7 70 -1 -1 3.000 0 0 7 0 0 5 5100 4200 8625 4200 8625 6450 5100 6450 5100 4200 2 2 0 1 0 34 50 -1 28 0.000 0 0 -1 0 0 5 2475 4725 3675 4725 3675 5175 2475 5175 2475 4725 2 2 0 1 0 34 50 -1 28 0.000 0 0 -1 0 0 5 5325 4725 6375 4725 6375 5175 5325 5175 5325 4725 2 2 0 1 0 34 50 -1 28 0.000 0 0 -1 0 0 5 7350 5700 8475 5700 8475 6150 7350 6150 7350 5700 2 2 0 1 0 34 50 -1 28 0.000 0 0 -1 0 0 5 7350 4725 8475 4725 8475 5175 7350 5175 7350 4725 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 6375 5625 6375 6225 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 5325 5625 5325 6225 2 2 2 0 0 33 55 -1 20 3.000 0 0 7 0 0 5 5325 5625 6375 5625 6375 6225 5325 6225 5325 5625 2 1 0 1 0 7 50 -1 -1 0.000 0 0 7 0 1 3 1 1 1.00 60.00 120.00 2475 4950 1875 4950 1875 5625 4 0 0 50 -1 0 10 0.0000 6 105 315 6675 4800 WOI\001 4 0 0 50 -1 0 10 0.0000 6 105 570 6525 5850 data-bins\001 4 0 0 50 -1 0 10 0.0000 6 105 315 7350 5475 WOI\001 4 0 0 50 -1 0 10 0.0000 6 105 570 4125 5175 data-bins\001 4 0 0 50 -1 0 10 0.0000 6 105 390 1350 4500 Server\001 4 0 0 50 -1 0 10 0.0000 6 105 405 5250 4500 Client\001 4 0 0 50 -1 0 10 0.0000 6 90 375 6600 5175 status\001 4 0 0 50 -1 0 10 0.0000 6 105 360 5625 6000 Cache\001 4 0 0 50 -1 0 10 0.0000 6 135 360 8025 5475 image\001 4 0 0 50 -1 0 10 0.0000 6 105 525 7650 5025 Browser\001 4 0 0 50 -1 0 10 0.0000 6 105 690 5475 5025 JPIP client\001 4 0 0 50 -1 0 10 0.0000 6 150 795 4050 4800 WOI request\001 4 0 0 50 -1 0 10 0.0000 6 105 750 2625 5925 Client cache\001 4 0 0 50 -1 0 10 0.0000 6 105 390 2850 6150 model\001 4 0 0 50 -1 0 10 0.0000 6 105 645 1500 5925 JPEG2000\001 4 0 0 50 -1 0 10 0.0000 6 135 420 1650 6150 images\001 4 0 0 50 -1 0 10 0.0000 6 105 705 2700 5025 JPIP server\001 4 0 0 50 -1 0 10 0.0000 6 150 870 7500 6000 Decompressor\001 esajpip-0.1~bzr33/doc/architecture.fig0000644000175000017500000001063412335423210017656 0ustar mathieumathieu#FIG 3.2 Produced by xfig version 3.2.5b Landscape Center Inches Letter 100.00 Single -2 1200 2 0 32 #e7e7e7 0 33 #b6d5ae 0 34 #aeb2d5 6 8250 5850 9300 6600 6 8250 5850 9300 6600 1 2 0 1 0 33 56 -1 20 0.000 1 0.0000 8779 6525 521 75 8258 6450 9300 6600 1 2 0 1 0 33 50 -1 30 0.000 1 0.0000 8779 5925 521 75 8258 5925 9300 5925 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 8250 5925 8250 6525 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 9300 5925 9300 6525 2 2 0 0 0 33 55 -1 20 0.000 0 0 7 0 0 5 8250 5925 9300 5925 9300 6525 8250 6525 8250 5925 4 0 0 50 -1 0 10 0.0000 6 105 645 8400 6225 JPEG2000\001 4 0 0 50 -1 0 10 0.0000 6 135 420 8550 6450 images\001 -6 -6 6 5700 3900 6675 4500 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4 5700 4425 5700 3900 6675 3900 6675 4425 3 2 0 1 0 7 50 -1 -1 0.000 0 0 0 7 5700 4423 5819 4482 5992 4482 6169 4423 6342 4367 6525 4350 6675 4425 0.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.000 -6 6 5700 4800 6675 5400 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4 5700 5325 5700 4800 6675 4800 6675 5325 3 2 0 1 0 7 50 -1 -1 0.000 0 0 0 7 5700 5323 5819 5382 5992 5382 6169 5323 6342 5267 6525 5250 6675 5325 0.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.000 -6 6 5775 3225 6600 3525 4 0 0 50 -1 0 8 0.0000 6 90 825 5775 3375 UNIX domain\001 4 0 0 50 -1 0 8 0.0000 6 90 375 6000 3525 socket\001 -6 6 7275 2700 7875 3900 2 2 0 1 0 34 50 -1 28 0.000 0 0 -1 0 0 5 7275 2700 7875 2700 7875 3900 7275 3900 7275 2700 2 2 0 1 0 32 49 -1 20 0.000 0 0 -1 0 0 5 7575 2775 7800 2775 7800 3825 7575 3825 7575 2775 4 0 0 50 -1 0 10 1.5708 6 135 945 7500 3825 Client manager\001 4 0 0 48 -1 0 8 1.5708 6 90 885 7725 3750 Data-bin server\001 -6 6 8475 2700 9075 3900 2 2 0 1 0 34 50 -1 28 0.000 0 0 -1 0 0 5 8475 2700 9075 2700 9075 3900 8475 3900 8475 2700 2 2 0 1 0 32 49 -1 20 0.000 0 0 -1 0 0 5 8775 2775 9000 2775 9000 3825 8775 3825 8775 2775 4 0 0 50 -1 0 10 1.5708 6 135 945 8700 3825 Client manager\001 4 0 0 48 -1 0 8 1.5708 6 90 885 8925 3750 Data-bin server\001 -6 1 2 0 1 0 33 50 -1 30 0.000 1 0.0000 7579 5925 521 75 7058 5925 8100 5925 1 2 0 1 0 33 56 -1 20 0.000 1 0.0000 7579 6525 521 75 7058 6450 8100 6600 1 2 2 1 0 7 50 -1 -1 3.000 1 0.0000 6150 3098 75 127 6075 3098 6225 3098 2 1 0 1 0 7 50 -1 -1 0.000 0 0 7 1 0 4 1 1 1.00 60.00 120.00 8775 5925 8775 5625 8325 5625 8325 5325 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 8175 4650 8175 5025 2 2 0 1 0 34 50 -1 28 0.000 0 0 -1 0 0 5 7575 5025 8775 5025 8775 5325 7575 5325 7575 5025 2 2 0 1 0 34 50 -1 28 0.000 0 0 -1 0 0 5 7575 4350 8775 4350 8775 4650 7575 4650 7575 4350 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2 1 1 1.00 60.00 120.00 8175 4350 8175 4125 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 4 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 7575 3900 7575 4125 8775 4125 8775 3900 2 2 2 1 0 7 70 -1 -1 3.000 0 0 7 0 0 5 7125 2550 9225 2550 9225 5550 7125 5550 7125 2550 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 4 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 7575 5925 7575 5625 7950 5625 7950 5325 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 7050 5925 7050 6525 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 8100 5925 8100 6525 2 2 0 0 0 33 55 -1 20 0.000 0 0 7 0 0 5 7050 5925 8100 5925 8100 6525 7050 6525 7050 5925 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 5250 3075 7125 3075 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 6675 5025 7125 5025 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 5250 5025 5700 5025 2 2 2 1 0 7 70 -1 -1 3.000 0 0 7 0 0 5 4575 2550 5250 2550 5250 5475 4575 5475 4575 2550 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2 1 1 1.00 60.00 120.00 5250 4125 5700 4125 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6675 4125 7125 4125 4 0 0 50 -1 0 10 0.0000 6 135 900 7725 4575 Index manager\001 4 0 0 50 -1 0 10 0.0000 6 135 795 7725 5250 File manager\001 4 0 0 50 -1 0 10 0.0000 6 135 720 7200 6225 Image cache\001 4 0 0 50 -1 0 10 0.0000 6 105 285 7425 6450 files\001 4 0 0 50 -1 0 10 0.0000 6 150 840 7125 2475 Child process\001 4 0 0 50 -1 0 9 0.0000 6 135 885 5775 4125 Configuration\001 4 0 0 50 -1 0 9 0.0000 6 135 735 5850 4275 (server.cfg)\001 4 0 0 50 -1 0 9 0.0000 6 135 735 5850 5025 App. shared\001 4 0 0 50 -1 0 9 0.0000 6 105 750 5850 5175 information\001 4 0 0 50 -1 0 10 0.0000 6 150 885 4425 2475 Father process\001 4 0 0 50 -1 0 16 0.0000 6 30 300 8025 3450 . . .\001 esajpip-0.1~bzr33/doc/jpip.tex0000644000175000017500000003560612335423210016177 0ustar mathieumathieu Part 9 of the JPEG2000 standard is almost completely dedicated to the development of systems for remote browsing of images. It defines a set of technologies (protocols, file formats, architectures, etc.) that allow to exploit efficiently all the characteristics of the JPEG2000 compression system for the development of this kind of systems. The technology which Part 9 mainly focuses on is the JPIP protocol (JPeg2000 Interactive Protocol). \subsection{Architecture} The common client/server architecture of a system for remote browsing of images that uses the JPIP transmission protocol has the organization shown in Fig. \ref{fig:jpip}. \begin{figure} \resizebox{\textwidth}{!}{ \input{../jpip_fig} } \caption{Client/server architecture of the JPIP protocol.} \label{fig:jpip} \end{figure} As it can be observed in the figure, the client is divided into four functional modules. The Browser module consists of the interface which the user interacts with in order to define the desired WOI. JPIP allows to use multiple parameters to define the WOI of the remote image to show in form of restrictions related to the partitions to transmit (number of quality layers, components, etc.). Geometrically, JPIP always imposes that the WOIs have to be defined in rectangular regions over a certain resolution level. Once the user has defined the desired WOI, it is sent to the ``JPIP client'' and ``Decompressor'' modules. The first one is the responsible for communicating to the JPIP server in order to send it the WOI using the messages and syntax defined by JPIP. When the server receives this information, it extracts from the associated image the required data for the reconstruction of the WOI, and send it to the client. This data is sent encapsulated in data-bins. In JPIP the different elements of the data partitions of a JPEG2000 image are reordered and encapsulated in data-bins, being the transmission units. As the client receives the data-bins from the server, it stores them in a internal cache (``Cache'' module). The client cache is organized in data-bins as well. This cache is continuously used by the ``Decompressor'' module for generating progressive reconstructions of the WOI, that are passed to the ``Browser'' module to show to the user. As it can be seen, except the ``Cache'' module which serves as a container, the rest of the modules that composes the client work in parallel. The Browser is continuously indicating to the JPIP client which WOI is wanted by the user. The JPIP client keeps communicating to the server for transmitting this WOI and, as it receives the data, stores it within the cache. The decompressor generates every time reconstructions of the current WOI with the existing data in the cache. The modules begin their execution when the user defines the first WOI, and they stop when all the data of the current WOI have been received. The user can indicate a new WOI whenever, without having to wait for the completion of the previous one. The client cache stores all the data-bins received from the server, for all the WOIs of all the images explored by the user. The server maintains a model of the content of this cache, that allows it to avoid to send to the client data that it already has. For instance, let's assume a user, after exploring a certain $WOI_A$, requests then a new $WOI_B$ that has an overlapping with $WOI_A$. If a server maintains updated the cache model of the content of the client cache of the user, when the $WOI_B$ is requested, the server only sends the data-bins necessary to reconstruct the part of $WOI_B$ that is not in common with $WOI_A$. If all the data-bins that allow to construct a certain $WOI_i$ are defined by $D(WOI_i)$, we can say that the server sends the data-bins $D(WOI_B) - \left( D(WOI_A) \bigcap D(WOI_B) \right)$. The JPIP protocol was designed to be independent of the used base protocol. However, the \href{http://www.ietf.org/rfc/rfc2616.txt} {HTTP protocol} is mainly used as base protocol, because of the similarity of the syntax with JPIP. Moreover, when the communication is based on HTTP, the \href{http://en.wikipedia.org/wiki/Chunked_transfer_encoding} {chunked transfer encoding} is commonly used. The ESA JPIP server always uses this kind of communication. \subsection{Data-bin partition} \label{sec:data-bins} Data-bins encapsulate different items of the partition of a JPEG2000 image. This new partition of data defined by JPIP permits to identify and gather the different parts of an image for their transmission. In the server code, the class \hyperlink{classjpip_1_1DataBinWriter}{jpip::DataBinWriter} is the responsible to generate the data-bins for the transmission. When a client/server communication is started, it is defined which kind of data-bin stream is going to be used. JPIP defines two kinds of streams, JPP, oriented to precincts, and JPT, oriented to tiles. The stream type indicates what kind of data-bins are used for the data transmission. The most used stream type is JPP and is the only one supported by the ESA JPIP server. Each data-bin is unequivocally identified by the image or code-stream to what belongs, the data-bin type and its identifier. This information is included in the header of each data-bin. The data-bins can be segmented for theirs transmission. A certain set of data-bins can be divided into a random number of segments, and they can be sent following any order. Each segment of data-bin includes the necessary information for its correct identification. In Table \ref{tab:data-bins} the relation of the different types of data-bins defined in JPIP can be observed, showing which stream type they belongs and what information they contain. Next the main kinds of data-bins are explained: \begin{table} \begin{center} \begin{tabular}[]{{l}{l}{l}} \textbf{Data-bin} & \textbf{Stream} & \textbf{Contained information} \\ \hline \hline Precinct & JPP & All the packets of a precinct. \\\hline Precinct extended & JPP & The same content with additional content. \\\hline Tile & JPT & All the packets and markers of a tile.\\\hline Tile extended & JPT & The same content with additional content. \\\hline Tile header & JPT & The markers of the header of tile. \\\hline Header & JPP/JPT & The markers of the header of a code-stream. \\\hline Meta-data & JPP/JPT & Meta-data of an image. \\ \hline \hline \end{tabular} \caption{List of the data-bins defined by JPIP.} \label{tab:data-bins} \end{center} \end{table} \begin{itemize} \item \textbf{Precinct data-bin:} Contains all the packets of a precinct for a resolution $r$, a component $c$ and a tile $t$. The packets are ordered within a data-bin for quality layer, in increasing order. Every precinct data-bin is identified by an index $I$ that is obtained by means of the following expression: \begin{equation*} I = t + \left( (c + (s \times N_c)) \times N_t \right) \end{equation*} $N_c$ y $N_t$ are the number of components and the number of tiles of the image to which the precinct belongs, respectively. The index of tile, $t$, as well as the index of component $c$ and the value $s$ begin with zero. To every precinct of every tile-component, including all the resolutions, an unique number of sequence $s$ is assigned. To all the precincts of the lowest resolution a number of sequence is assigned that starts with zero to the one located in the left-top border, and that continues increasing by column and row respectively. In the next resolutions a correlative sequence number is assigned to the precincts in the same way. \item \textbf{Tile data-bin:} Contains all the packets and markers associated to a tile. It is composed by concatenating all the tile-parts associated to a tile, including the markers SOT, SOD and all the rest relevant markers. The data-bins of this kind are identified by means of an incremental index, beginning with zero for the tile located in the top-left border. \item \textbf{Tile header data-bin:} Contains all the markers associated to a certain tile. It is formed by all the markers of the headers of all the tile-parts of a tile, without including neither the SOT nor the SOD markers. The identifier of this data-bin has the same numeration that in the case of the tile. \item \textbf{Header data-bin:} Contains the main header of the code-stream, from the SOC (included) to the first SOT marker (not included). Neither the SOD nor the EOC marker is included either. \item \textbf{Meta-data bins:} These data-bins appear only if the associated image is a file of the JP2 family. The meta data-bins contain a set of boxes of the image file. The standard does not define how these data-bins must be identified nor within which boxes must be stored, but when a meta data-bin is identified by zero, means that it will include all the boxes contained by an image. \end{itemize} \subsection{Sessions and channels} A request of the client to the server can be either stateful or stateless. The stateful requests are carried out within the context of a communication session, which state is maintained by the server. The stateless requests do not require any session. The use of sessions improve the performance of the server because, for example, when establishing a session with a certain image file, the server opens that file and prepares it in order to be transmitted in data-bins, so all the requests associated to that same session do not provoke that the server makes again that process. The stateless requests can be considered as unique sessions that end when the server response ends. Under a session, using stateful requests, the client can open multiple channels, being able to perform multiple stateful requests associated to the same session simultaneously. This is specially useful for applications that show simultaneously different regions of interest of the same image. The channels can be closed and opened in independently, without affecting to the session. To close a session would involve to close all the channels opened associated to it. A set of images is associated to each session. A session implies that the server maintains a model of the client cache. That model will be only maintained while the session remains active. A channel, for a certain session, is associated to a certain image and a kind of specific data-bin stream (JPP or JPT). The channel is identified in a unequivocal way by means of a alphanumeric assigned by the server, and which format is completely free. The sessions are not identified, since the identifier of the channel must be enough to identify the channel as well as the session to which belongs. Many times clients are interested to maintain in the server the client cache model between different sessions. The server by default does not allow this possibility, beginning a new session with a client always with a model of cache empty, although the client cache contains initial information. In this case JPIP defines a set of messages that allow the client to modify the model that the server of its cache. Therefore, when the client starts a new session with a server, it would send a resume of the current content of its cache to improve the communication and to avoid redundancy, usually by means of a POST message. The cache models maintained by the servers not only allow to avoid the redundancy between messages, but they are also used in order to allow the client to perform incremental requests and control the stream of data. Clients can indicate in their requests a parameter with the maximum length of the server response. Thanks to the cache model of the server, the client can perform successive identical requests, but varying that parameters, so the server sends as response increments of information. Therefore the client has certain control and can adapt the stream of information to the available bandwidth and delay, but always taking into account that the server can modify whenever the related parameter. This way of communication is indeed the most common one in the existing implementations of JPIP. \subsection{Messages} The JPIP requests are formed by means of a ASCII sequence of pairs ``parameter $=$ value''. This allows that a JPIP request can be encapsulated within a GET message of the HTTP protocol, next to the character '?', concatenating all the pairs with the symbol '\&'. It is hence formed a typical HTTP request when dynamic objects are referenced like CGI. Some of the available parameters for a JPIP request are the followings: \begin{itemize} \item \textbf{``fsiz=$R_{x}$,$R_{y}$'':} Specifies the resolution associated to the required region of interest. The server chooses the biggest resolution of the image so its dimension $R_{x}' \times R_{y}'$ satisfies that $R_{x}' \geq R_{x}$ and $R_{y}' \geq R_{y}$. In general this parameter includes the resolution of the user screen. \item \textbf{``roff=$P_{x}$,$P_{y}$'':} Specifies the position of the upper left border of the required region of interest within the indicated resolution. If this position is not indicated, the server assumes the value $(0,0)$. \item \textbf{``rsiz=$S_{x}$,$S_{y}$'':} Specifies the size of the required region of interest. The server cuts this size in order to fit it into the real image according to the specified resolution. \item \textbf{``len=number of bytes'':} Client tells with this parameter to the server the maximum number of bytes that it can include in the response. The server takes into account this limit, not only in the response to the current request, but in the rest of the next client responses within the same session. \item \textbf{``target=image'':} This parameter identifies the image file from which to extract the specified region of interest. When the HTTP protocol is used, this parameter is not necessary since the name of the image is obtained from the own URL specified in the GET message. \item \textbf{``cnew=protocol'':} When the client wants to open a new channel under the same session, it uses this parameter, indicating the protocol that must be used for this new channel. The types of valid base protocols are ``http'' and ``http-tcp''. \item \textbf{``cid=channel identifier'':} When the client creates a new channel, the server sends the channel identifier, that must be included in all the requests associated to that channel. \item \textbf{``cclose=channel identifier'':} The client may decide to close certain channel by means of this parameter, just specifying the identifier of that channel. \item \textbf{``type=stream type'':} When a new channel is created, the client indicates what kind of data-bin stream is wanted. The main types of data-bin streams are JPP (``jpp-stream'') and JPT (``jpt-stream''). \item \textbf{``model=\ldots'':} How it has been commented previously, the client can need to tell to the server the content of its cache in order to update the content of the cache model maintained by the last one. For example, \texttt{model=Hm,H*,M2,P0:20} would tell the server to include in the cache model the main header of the code-stream, the headers of all the tiles, the meta data-bin number 2 and the first $20$ bytes of the precinct $0$. \end{itemize} esajpip-0.1~bzr33/doc/codestream.fig0000644000175000017500000001255512335423210017326 0ustar mathieumathieu#FIG 3.2 Produced by xfig version 3.2.5 Landscape Center Metric A4 100.00 Single -2 1200 2 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 1980 4050 3150 6660 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 1980 3375 3150 585 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 60.00 1 1 1.00 60.00 60.00 4230 585 4230 1530 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 60.00 1 1 1.00 60.00 60.00 4230 2475 4230 3420 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 60.00 1 1 1.00 60.00 60.00 4230 4770 4230 5715 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3960 1530 4230 1530 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3960 3420 4230 3420 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3960 5715 4230 5715 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3960 585 6030 585 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3960 2475 6030 2475 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3960 4770 6030 4770 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3960 6660 6030 6660 2 2 0 1 0 0 50 -1 3 0.000 0 0 -1 0 0 5 1170 4950 1980 4950 1980 5625 1170 5625 1170 4950 2 2 0 1 0 0 50 -1 3 0.000 0 0 -1 0 0 5 1170 4050 1980 4050 1980 4725 1170 4725 1170 4050 2 2 0 1 0 0 50 -1 3 0.000 0 0 -1 0 0 5 1170 3375 1980 3375 1980 4050 1170 4050 1170 3375 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 3150 4770 3960 4770 3960 5130 3150 5130 3150 4770 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 3150 3060 3960 3060 3960 3420 3150 3420 3150 3060 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 3150 2475 3960 2475 3960 2835 3150 2835 3150 2475 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 3150 1170 3960 1170 3960 1530 3150 1530 3150 1170 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 3150 585 3960 585 3960 945 3150 945 3150 585 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 1170 1260 1980 1260 1980 1620 1170 1620 1170 1260 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 3150 5355 3960 5355 3960 5715 3150 5715 3150 5355 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 1170 2790 1980 2790 1980 3150 1170 3150 1170 2790 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 1170 5625 1980 5625 1980 5985 1170 5985 1170 5625 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 1170 2205 1980 2205 1980 2565 1170 2565 1170 2205 2 2 0 1 0 1 50 -1 35 0.000 0 0 -1 0 0 5 1170 1620 1980 1620 1980 1980 1170 1980 1170 1620 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 3960 4365 6030 4365 2 2 0 1 0 15 50 -1 35 0.000 0 0 -1 0 0 5 3150 2205 3960 2205 3960 2475 3150 2475 3150 2205 2 2 0 1 0 15 50 -1 35 0.000 0 0 -1 0 0 5 3150 1530 3960 1530 3960 1980 3150 1980 3150 1530 2 2 0 1 0 15 50 -1 35 0.000 0 0 -1 0 0 5 3150 5715 3960 5715 3960 6030 3150 6030 3150 5715 2 2 0 1 0 15 50 -1 35 0.000 0 0 -1 0 0 5 3150 6255 3960 6255 3960 6660 3150 6660 3150 6255 2 2 0 1 0 15 50 -1 35 0.000 0 0 -1 0 0 5 3150 3420 3960 3420 3960 3690 3150 3690 3150 3420 2 2 0 1 0 15 50 -1 35 0.000 0 0 -1 0 0 5 3150 3915 3960 3915 3960 4365 3150 4365 3150 3915 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 60.00 1 1 1.00 60.00 60.00 6030 585 6030 2475 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 60.00 1 1 1.00 60.00 60.00 6030 2475 6030 4365 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 60.00 1 1 1.00 60.00 60.00 6030 4770 6030 6660 4 1 0 50 -1 0 11 0.0000 6 135 720 3600 1125 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 135 270 3555 810 SOT\001 4 1 0 50 -1 0 11 0.0000 6 135 270 3555 1440 SOD\001 4 1 0 50 -1 0 11 0.0000 6 135 720 3600 4635 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 135 720 1620 2160 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 135 720 1620 2745 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 135 720 1620 3330 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 135 720 1620 4905 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 135 270 1575 1530 SOC\001 4 1 0 50 -1 0 11 0.0000 6 135 270 1575 1890 SIZ\001 4 1 0 50 -1 0 11 0.0000 6 135 270 1575 2475 COD\001 4 1 0 50 -1 0 11 0.0000 6 150 270 1575 3060 QCD\001 4 1 0 50 -1 0 11 0.0000 6 135 270 1575 5895 SOC\001 4 1 0 50 -1 0 11 0.0000 6 135 720 3600 3015 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 135 270 3555 2700 SOT\001 4 1 0 50 -1 0 11 0.0000 6 135 270 3555 3330 SOD\001 4 1 0 50 -1 0 11 0.0000 6 135 720 3600 5310 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 135 270 3555 4995 SOT\001 4 1 0 50 -1 0 11 0.0000 6 135 270 3555 5625 SOD\001 4 1 0 50 -1 0 11 0.0000 6 165 540 3555 5940 packet\001 4 1 0 50 -1 0 11 0.0000 6 165 540 3555 2385 packet\001 4 1 0 50 -1 0 11 0.0000 6 135 720 3600 2160 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 165 540 3555 1800 packet\001 4 1 0 50 -1 0 11 0.0000 6 135 720 3600 6210 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 165 540 3555 6480 packet\001 4 1 0 50 -1 0 11 0.0000 6 165 540 3555 3600 packet\001 4 1 0 50 -1 0 11 0.0000 6 135 720 3600 3870 $\\cdots$\001 4 1 0 50 -1 0 11 0.0000 6 165 540 3555 4185 packet\001 4 1 0 50 -1 0 11 0.0000 6 135 360 1575 3780 tile\001 4 1 0 50 -1 0 11 0.0000 6 135 360 1575 4410 tile\001 4 1 0 50 -1 0 11 0.0000 6 135 360 1575 5355 tile\001 4 0 0 50 -1 0 11 0.0000 6 135 630 4320 1350 or tile\001 4 0 0 50 -1 0 11 0.0000 6 165 1350 4320 1125 first tile-part\001 4 0 0 50 -1 0 11 0.0000 6 135 1170 4320 900 Header of the\001 4 0 0 50 -1 0 11 0.0000 6 165 810 6075 3465 tile-part\001 4 0 0 50 -1 0 11 0.0000 6 165 810 6075 5760 tile-part\001 4 0 0 50 -1 0 11 0.0000 6 165 810 4320 5310 tile-part\001 4 0 0 50 -1 0 11 0.0000 6 135 1170 4320 5085 Header of the\001 4 0 0 50 -1 0 11 0.0000 6 165 810 6075 1575 tile-part\001 4 0 0 50 -1 0 11 0.0000 6 165 810 4320 3015 tile-part\001 4 0 0 50 -1 0 11 0.0000 6 135 1260 4320 2790 Header of the \001 esajpip-0.1~bzr33/doc/doxygen.sty0000644000175000017500000001617412335423210016730 0ustar mathieumathieu\NeedsTeXFormat{LaTeX2e} \ProvidesPackage{doxygen} % Packages used by this style file \RequirePackage{alltt} \RequirePackage{array} \RequirePackage{calc} \RequirePackage{color} \RequirePackage{fancyhdr} \RequirePackage{verbatim} % Setup fancy headings \pagestyle{fancyplain} \newcommand{\clearemptydoublepage}{% \newpage{\pagestyle{empty}\cleardoublepage}% } \renewcommand{\chaptermark}[1]{% \markboth{#1}{}% } \renewcommand{\sectionmark}[1]{% \markright{\thesection\ #1}% } \newcommand{\SERVER}{ \fancyplain{}{\bfseries SOHO JPIP server} } \lhead[\SERVER]{\fancyplain{}{\bfseries\rightmark}} \rhead[\fancyplain{}{\bfseries\leftmark}]{\SERVER} \rfoot[]{\fancyplain{}{\bfseries\thepage}} \lfoot[\fancyplain{}{\bfseries\thepage}]{} \cfoot{} %---------- Internal commands used in this style file ---------------- % Generic environment used by all paragraph-based environments defined % below. Note that the command \title{...} needs to be defined inside % those environments! \newenvironment{DoxyDesc}[1]{% \begin{list}{}% {% \settowidth{\labelwidth}{40pt}% \setlength{\leftmargin}{\labelwidth}% \setlength{\parsep}{0pt}% \setlength{\itemsep}{-4pt}% \renewcommand{\makelabel}{\entrylabel}% }% \item[#1]% }{% \end{list}% } %---------- Commands used by doxygen LaTeX output generator ---------- % Used by
 ... 
\newenvironment{DoxyPre}{% \small% \begin{alltt}% }{% \end{alltt}% \normalsize% } % Used by @code ... @endcode \newenvironment{DoxyCode}{% \footnotesize% \verbatim% }{% \endverbatim% \normalsize% } % Used by @example, @include, @includelineno and @dontinclude \newenvironment{DoxyCodeInclude}{% \DoxyCode% }{% \endDoxyCode% } % Used by @verbatim ... @endverbatim \newenvironment{DoxyVerb}{% \footnotesize% \verbatim% }{% \endverbatim% \normalsize% } % Used by @verbinclude \newenvironment{DoxyVerbInclude}{% \DoxyVerb% }{% \endDoxyVerb% } % Used by numbered lists (using '-#' or
    ...
) \newenvironment{DoxyEnumerate}{% \enumerate% }{% \endenumerate% } % Used by bullet lists (using '-', @li, @arg, or ) \newenvironment{DoxyItemize}{% \itemize% }{% \enditemize% } % Used by description lists (using
...
) \newenvironment{DoxyDescription}{% \description% }{% \enddescription% } % Used by @image, @dotfile, and @dot ... @enddot % (only if caption is specified) \newenvironment{DoxyImage}{% \begin{figure}[H]% \begin{center}% }{% \end{center}% \end{figure}% } % Used by @image, @dotfile, @dot ... @enddot, and @msc ... @endmsc % (only if no caption is specified) \newenvironment{DoxyImageNoCaption}{% }{% } % Used by @attention \newenvironment{DoxyAttention}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @author and @authors \newenvironment{DoxyAuthor}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @date \newenvironment{DoxyDate}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @invariant \newenvironment{DoxyInvariant}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @note \newenvironment{DoxyNote}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @post \newenvironment{DoxyPostcond}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @pre \newenvironment{DoxyPrecond}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @remark \newenvironment{DoxyRemark}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @return \newenvironment{DoxyReturn}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @since \newenvironment{DoxySince}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @see \newenvironment{DoxySeeAlso}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @version \newenvironment{DoxyVersion}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @warning \newenvironment{DoxyWarning}[1]{% \begin{DoxyDesc}{#1}% }{% \end{DoxyDesc}% } % Used by @internal \newenvironment{DoxyInternal}[1]{% \paragraph*{#1}% }{% } % Used by @par and @paragraph \newenvironment{DoxyParagraph}[1]{% \begin{list}{}% {% \settowidth{\labelwidth}{40pt}% \setlength{\leftmargin}{\labelwidth}% \setlength{\parsep}{0pt}% \setlength{\itemsep}{-4pt}% \renewcommand{\makelabel}{\entrylabel}% }% \item[#1]% }{% \end{list}% } % Used by parameter lists \newenvironment{DoxyParams}[1]{% \begin{DoxyDesc}{#1}% \begin{description}% }{% \end{description}% \end{DoxyDesc}% } % is used for parameters within a detailed function description \newenvironment{DoxyParamCaption}{% \renewcommand{\item}[2][]{##1 {\em ##2}}% }{% } % Used by return value lists \newenvironment{DoxyRetVals}[1]{% \begin{DoxyDesc}{#1}% \begin{description}% }{% \end{description}% \end{DoxyDesc}% } % Used by exception lists \newenvironment{DoxyExceptions}[1]{% \begin{DoxyDesc}{#1}% \begin{description}% }{% \end{description}% \end{DoxyDesc}% } % Used by template parameter lists \newenvironment{DoxyTemplParams}[1]{% \begin{DoxyDesc}{#1}% \begin{description}% }{% \end{description}% \end{DoxyDesc}% } \newcommand{\doxyref}[3]{\textbf{#1} (\textnormal{#2}\,\pageref{#3})} \newenvironment{DoxyCompactList} {\begin{list}{}{ \setlength{\leftmargin}{0.5cm} \setlength{\itemsep}{0pt} \setlength{\parsep}{0pt} \setlength{\topsep}{0pt} \renewcommand{\makelabel}{\hfill}}} {\end{list}} \newenvironment{DoxyCompactItemize} { \begin{itemize} \setlength{\itemsep}{-3pt} \setlength{\parsep}{0pt} \setlength{\topsep}{0pt} \setlength{\partopsep}{0pt} } {\end{itemize}} \newcommand{\PBS}[1]{\let\temp=\\#1\let\\=\temp} \newlength{\tmplength} \newenvironment{TabularC}[1] { \setlength{\tmplength} {\linewidth/(#1)-\tabcolsep*2-\arrayrulewidth*(#1+1)/(#1)} \par\begin{tabular*}{\linewidth} {*{#1}{|>{\PBS\raggedright\hspace{0pt}}p{\the\tmplength}}|} } {\end{tabular*}\par} \newcommand{\entrylabel}[1]{ {\parbox[b]{\labelwidth-4pt}{\makebox[0pt][l]{\textbf{#1}}\vspace{1.5\baselineskip}}}} \newenvironment{Desc} {\begin{list}{} { \settowidth{\labelwidth}{40pt} \setlength{\leftmargin}{\labelwidth} \setlength{\parsep}{0pt} \setlength{\itemsep}{-4pt} \renewcommand{\makelabel}{\entrylabel} } } {\end{list}} \newenvironment{Indent} {\begin{list}{}{\setlength{\leftmargin}{0.5cm}} \item[]\ignorespaces} {\unskip\end{list}} \setlength{\parindent}{0cm} \setlength{\parskip}{0.2cm} \addtocounter{secnumdepth}{1} \sloppy \usepackage[T1]{fontenc} \makeatletter \renewcommand{\paragraph}{\@startsection{paragraph}{4}{0ex}% {-3.25ex plus -1ex minus -0.2ex}% {1.5ex plus 0.2ex}% {\normalfont\normalsize\bfseries}} \makeatother \stepcounter{secnumdepth} \stepcounter{tocdepth} \definecolor{comment}{rgb}{0.5,0.0,0.0} \definecolor{keyword}{rgb}{0.0,0.5,0.0} \definecolor{keywordtype}{rgb}{0.38,0.25,0.125} \definecolor{keywordflow}{rgb}{0.88,0.5,0.0} \definecolor{preprocessor}{rgb}{0.5,0.38,0.125} \definecolor{stringliteral}{rgb}{0.0,0.125,0.25} \definecolor{charliteral}{rgb}{0.0,0.5,0.5} \definecolor{vhdldigit}{rgb}{1.0,0.0,1.0} \definecolor{vhdlkeyword}{rgb}{0.43,0.0,0.43} \definecolor{vhdllogic}{rgb}{1.0,0.0,0.0} \definecolor{vhdlchar}{rgb}{0.0,0.0,0.0} esajpip-0.1~bzr33/doc/guide.tex0000644000175000017500000006472412335423210016335 0ustar mathieumathieu\chapter{User guide} \section{Introduction} \label{introduction} The ESA JPIP server is capable to handle the following types of JPEG2000 image files: raw J2C, JP2 and JPX with or without hyperlinks. The codestreams of the images must comply with the following requirements: \begin{itemize} \item No tiles partition is allowed. \item The progression order must be LRCP, RLCP or RPCL. \item PLT markers must be included with the information of all the packets. \end{itemize} If one image does not fit these requirements then it can not be served by this server. Moreover, although they are not mandatory, the following requirements are strongly recommended: \begin{itemize} \item No tile-parts. \item Use the RPCL progression order. \item Use an appropriate precinct partition. \end{itemize} The ESA JPIP server does not transcode the images at all, serving them as it. Therefore the last requirement is particularly recommended for big images in order to improve the transmission efficiency. For resolution levels bigger than $1024 \times 1024$ precincts of $512 \times 512$ or $256 \times 256$ are recommended. \section{Installation} In order to install the server it is necessary to get the code (for example, from \href{https://code.launchpad.net/esajpip}{Launchpad}) and compile it. The code of the server has been specifically written for Linux systems, so it has not been tested in any other platform. For compiling the source code the libraries libproc, log4cpp and libconfig++ must be installed, for developing, on the system (see Section \ref{libraries} for more details about these used libraries). Just by means of one ``make'' the compilation is performed. If ``make doc'' is used, this documentation is created automatically mixing this text with the source code documentation (\href{http://www.stack.nl/~dimitri/doxygen/}{Doxygen} and LaTeX are required to be installed). In order to get running the application it is only necessary to modify the configuration file as needed (see Section \ref{config}) and to have a caching directory with the write permission enabled for the server. \section{Configuration} \label{config} The configuration of the different parameters of the server is carried out by means of the file ``server.cfg'', which must be located in the same directory where the server is launched. The structure of this file is: \begin{itemize} \item Section ``\textit{listen\_at}'': \begin{itemize} \item Field ``\textit{port}'': Port used for listening. \item Field ``\textit{address}'': IP server address used for listening. This field can be empty meaning that the server will listen at any address available. \end{itemize} \item Section ``\textit{folders}'': \begin{itemize} \item Field ``\textit{images}'': Root of the folder where the images to serve are stored. \item Field ``\textit{caching}'': Root of the folder to store the cache files. \item Field ``\textit{logging}'': Folder to store the log files. \end{itemize} \item Section ``\textit{connections}'': \begin{itemize} \item Field ``\textit{time\_out}'': It defines the timeout (in seconds) of every connection. \item Field ``\textit{max\_number}'': The maximum number of simultaneous connections. \end{itemize} \item Section ``\textit{general}'': \begin{itemize} \item Field ``\textit{logging}'': It indicates if the log file is created (1 - Yes, 0 - No). \item Field ``\textit{cache\_max\_time}'': Expiration time of the cache files, in seconds. If this value is less than zero it means that no expiration time is used for the cache files. \item Field ``\textit{max\_chunk\_size}'': Maximum chunk size used for transmission, in bytes. \end{itemize} \end{itemize} Each time the server opens an image to be served, it creates a little associated cache file, if it does not exist yet, with the related indexing information, within the configured caching folder. Here is an example of a configuration file, which is the default one included in the Launchpad repository: \lstinputlisting[numbers=none,xleftmargin=50pt]{../../server.cfg} \section{Commands} \label{commands} The application accepts the following command line parameters: \begin{itemize} \item \textit{esa\_jpip\_server [start]}: It runs the server application. \item \textit{esa\_jpip\_server status}: It shows some information (memory, num. of connections, etc.) of the current server process. Currently the information shown is: \begin{itemize} \item The available total memory. \item The memory consumed by the father process. \item The memory consumed by the child process. \item The number of connections. \item The number of iterations (the number of times that the child process has been restarted). \item The number of threads of the child process. \item The CPU usage of the child process. \end{itemize} \item \textit{esa\_jpip\_server record [name\_file]}: It shows the same information in columns, being updated every 5 seconds. It accepts a third parameter, a name of a file where to store this information. \item \textit{esa\_jpip\_server stop [child]}: Both processes or only the child process (depending on the second parameter) associated to the current server running are finished. \item \textit{esa\_jpip\_server debug [child]}: It calls the debugger for the parent or child process depending on the second parameter. \item \textit{esa\_jpip\_server clean cache}: It removes all the cache files from the cache root folder which have exceeded the ``cache\_max\_time'' field from the ``server.cfg'' file. It also removes the existing ``.backup'' files from the same directory. \end{itemize} \chapter{Developer guide} \section{Introduction} The idea for the development of this application has been to implement a very stable and scalable solution of a JPIP server, specifically designed for Linux systems in order to fully profit from its characteristics. No portability strategies has been followed. The language chosen for the development is C++, writing the code following as much as possible the \href{http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml}{Google style guide}. The code is commented according to the Javadoc format, what allows to use the Doxygen tool and generate the documentation of the Part \ref{sourcecode} automatically. This documentation includes, if the tool \href{http://www.graphviz.org/}{Graphviz} is installed, the collaboration diagrams of all the classes, as well as the call diagrams of all the functions are generated. No libraries strictly related to the server performance have been used, except from the \href{http://www.sgi.com/tech/stl/}{standard STL library} and \href{https://computing.llnl.gov/tutorials/pthreads/}{pthread}. The used libraries (see Section \ref{libraries}) are only related to secondary features of the application. For the data/file operations the classes of the namespace \hyperlink{namespacedata}{data} are implemented. For example, the class \hyperlink{classdata_1_1BaseFile}{data::BaseFile} is a safe wrapper for the FILE related functions; the classes \hyperlink{classdata_1_1InputStream} {data::InputStream} and \hyperlink{classdata_1_1OutputStream} {data::OutputStream} allow the binary serialization of the classes; etc. Regarding the IPC and threads management operations the classes of the namespace \hyperlink{namespaceipc}{ipc} have been designed. For example, the class \hyperlink{classipc_1_1Mutex}{ipc::Mutex} implements the logic of a mutex; the class \hyperlink{classipc_1_1RdWrLock} {ipc::RdWrLock} implements a reader/writer lock based on the pthread\_rwlock functions; etc. Working with socket has been easy thanks to the classes of the namespace \hyperlink{namespacenet}{net}. For example, the class \hyperlink{classnet_1_1Socket}{net::Socket} offers a powerful interface for the socket Linux functions; the class \hyperlink{classnet_1_1SocketStream} {net::SocketStream} allows working with sockets as continuous data streams, compatible with the stream classes defined in the STL library; etc. Finally, for working with the HTTP protocol the classes of the namespace \hyperlink{namespacehttp}{http} have been implemented. Among others, the classes \hyperlink{classhttp_1_1Request}{http::Request} and \hyperlink{classhttp_1_1Response}{http::Response} permit to generate/generate HTTP messages, being compatible with the STL streams. With the help of the library \href{http://log4cpp.sourceforge.net/}{log4cpp} a trace system has been designed in order to easy the server logging as well as the debugging. The macros ``LOG'' and ``ERROR'' are defined to log information and error messages respectively, whilst the macro ``TRACE'' is defined to put debugging information in any part of the code. The debugging logs can be enabled/disabled by means of the macro ``SHOW\_TRACES''. For information see the content of the file \hyperlink{trace_8h}{trace.h}. Before explaining in detail the server architecture in Section \ref{sec:architecture}, some concepts of the JPEG2000 standard (Section \ref{sec:jpeg2000}), as well as the JPIP protocol (Section \ref{sec:jpip}) are explained, necessary to correctly understand the server code. The classes of the server code related to the JPEG2000 standard are defined in the namespace \hyperlink{namespacejpeg2000}{jpeg2000}. The classes for working with the JPIP protocol are located within the namespace \hyperlink{namespacejpip} {jpip}. Within the text of the following sections, references to some classes of these namespaces are given. \section{The JPEG2000 standard} \label{sec:jpeg2000} \input{../jpeg2000} \section{The JPIP protocol} \label{sec:jpip} \input{../jpip} \newpage \section{Server architecture} \label{sec:architecture} \begin{figure}[!b] \centering \resizebox{0.8\textwidth}{!}{ \input{../architecture} } \caption{Server architecture.} \label{fig:server} \end{figure} Fig. \ref{fig:server} shows a basic representation of the server architecture. It consists of a hybrid model combining both process and thread approaches. There are two processes, herein after called father and child. The first one creates the second one and is who listens for new client connections. When a new client connection is accepted by the father process, it sends this connection to the child process through a UNIX-domain socket in order to be attended. The child process is who provides all the functionality to handle the client connections. Each client connection is handled in the child process by a dedicated thread. The father process maintains a vector with all the open connections. When a connection is closed by the client, the child process notifies to the father process, through the UNIX-domain socket, in order to remove the connection from the vector. Since the father does not perform relevant operations, its probability of crashing due to an error is low. On the contrary, taking into account that the child process is how maintains all the image indexes and attends all the client connections, it may fail due to errors or not yet fixed bugs. When a process is crashed, all the related threads and connections are automatically closed. In the case of the child process, the current open connections are not closed because they are shared with the father process. This last can detect when the child process is down and launch a new child process. This new process, considering that it inherits the connections vector of the father process, it is capable to reestablish the connections without affecting the clients, that is, the clients do not notice when the child process crashes. This architecture provides a fault-tolerant and robust approach for the server, as well as it offers a good performance. The multi-threading solution implemented in the child process is efficient in terms of memory consumption and fast sharing/locking mechanisms. Having separated the client handling code from the father process provides robustness and security. In the source code of the main module \hyperlink{esa__jpip__server_8cc}{esa\_jpip\_server.cc} can be seen how this server architecture is created. The configuration of the server is read from the file ``server.cfg'' (see Section \ref{config} for details). This configuration is parsed by the class \hyperlink{classAppConfig}{AppConfig} and shared with both the father and child process. Between the father and child process is maintained a shared memory block, carried out by the class \hyperlink{classAppInfo}{AppInfo}. This allows to share information between the two processes, as well as to provide a mechanism for getting information from other processes, like in the case of the commands ``record'' and ``status'' (see Section \ref{commands}). The main parts of the child process, shown in Fig. \ref{fig:server}, are the File manager, the Index manager and the Client manager, that are explained in the following subsections. Every client connection is handled by a Client manager module, in an independent thread. This module manages the communication with the client, serving as the JPIP interface with the sub-module Data-bin server. This sub-module contains the code to properly generate the data-bins associated to the client requests, implementing as well the client cache model. The Index manager module is the responsible to manage the image indexes stored in memory. When client requests to open a certain JPEG2000 image, the related Client manager module requests the Index module for the associated indexing information. This module manages the indexing information in memory of all the currently open images by all the Client manager modules. The File manager module is in charge of parsing and extracting the indexing information of the image files that are requested by the Index manager module. The indexing information of each image is cached by means of little binary ``.cache'' files in order to avoid to repeat the indexing process when the same image is open several times. These cache files are stored in the directory specified in the configuration file. \subsection{File manager} The code of this module is contained in the class \hyperlink{classjpeg2000_1_1FileManager}{jpeg2000::FileManager}. Its main function is to extract the indexing information of the image files. The supported format files are J2C, JP2 and JPX, with or without hyperlinks. The files must also comply with the limitations specified in Section \ref{introduction}. The indexing information of an image file is stored in an instance of the class \hyperlink{classjpeg2000_1_1ImageInfo} {jpeg2000::ImageInfo}. It contains mainly a set of \hyperlink{classdata_1_1FileSegment} {data::FileSegment} objects (pair of offset and length information about a file segment) regarding the main headers, PLT segments, metadata segments, etc., of the image. The class \hyperlink{classjpeg2000_1_1ImageInfo} {jpeg2000::ImageInfo} as well as all of its members variables can be serialized using the serialization classes defined in the namespace \hyperlink{namespacedata}{data}. This makes easy load/save indexing information from the ``.cache'' files. When the Index manager requests to the File manager the indexing information of an image file, this last firstly checks whether the associated ``.cache'' file exists or not. If it exists, it just reads it, using the serialization to an \hyperlink{classjpeg2000_1_1ImageInfo}{jpeg2000::ImageInfo} object and returns it. If there is not any cache file yet, it opens the image file and parses it, generating the corresponding cache file. The cache files are stored in the directory defined in the configuration file, and they are named using the full path of the image files, replacing each directory separator '/' by underscores '\_', and adding the extension ``.cache''. The server does not remove any cache file during its execution. They can be removed either manually or by means of the server command ``clean cache'' using a LRU policy specified in the server configuration file (see Section \ref{commands}). \subsection{Index manager} The code of this module is contained in the class \hyperlink{classjpeg2000_1_1IndexManager}{jpeg2000::IndexManager}. Its main function is to manage the indexes of all the image files opened by the server. The index of each image is built from the indexing information retrieved from the file manager module. Notice that the indexing information generated by the file manager does not deal with packets, just the main parts of the image, like the position of the main header or the position of the PLT markers. From this initial information, the index manager builds a complete index of all the packets of each image. Each opened image is represented by an object of the class \hyperlink{classjpeg2000_1_1ImageIndex}{jpeg2000::ImageIndex}. All of these objects are handled by the index manager using a double linked list in memory. When a J2C, JP2 or JPX (without hyperlinks) image file is opened, a new \hyperlink{classjpeg2000_1_1ImageIndex}{jpeg2000::ImageIndex} is created, if it does not already exist, and inserted in the list. When a JPX image file with hyperlinks is opened, the index manager handles each contained hyperlink independently. In this case a new node is also created in the list, but it contains references to all the nodes associated to its hyperlinks. Some of them may already exist in the list, or they have been created. Each image node in the list contains a reference count When this count value gets zero, the node is removed from the list. The number of references is incremented each time a client manager requests for the associated image file, or when a JPX file is opened that contains a link to that image file. When a client manager opens a new channel, it requests to the index manager for the index of the image associated to this new channel. The index manager returns a reference of an object of the class \hyperlink{classjpeg2000_1_1ImageIndex}{jpeg2000::ImageIndex}. The packet index (handled by means of the class \hyperlink{classjpeg2000_1_1PacketIndex}{jpeg2000::PacketIndex}) of each image file is created on demand, by resolution level. In order to support this feature, the image file must be compressed with the progression order RPCL. On the contrary, the packet index is fully created at the beginning, when the image file is opened. This way of creating the index allows to adjust the memory consumption required for the indexes according to the user movements through the image. The modifications (inserting or removing nodes) of the list of indexes are controlled by a mutex lock. However, each index node contains its own independent locking mechanism for the modifications of the packet index. Multiple threads, associated each one to a client manager, can be working with the same image index node. If the packet index does not allow to be generated on demand, the main operation of all the threads over the packet index is to read. When the RPCL progression is used and the packet index can be built on demand, any thread can modify it (e.g. accessing to a new resolution level). A reader/writer lock mechanism has been chosen for controlling the modifications/accesses of the packet indexes, giving priority to the read operations (the most common ones) over the write operations. The class \hyperlink{classjpeg2000_1_1PacketIndex}{jpeg2000::PacketIndex} uses internally the class \hyperlink{classdata_1_1vint__vector} {data::vint\_vector} to stores the information of each packet. This class allows to use vectors of integers where each integer value can occupy a number of bytes not necessarily multiple of $2$. For example, if an image contains less than $2^{24}$ packets, each packet can be represented in the index by just $3$ bytes, instead of the minimal standard $4$ bytes. The information stored of each packet in the index vector is only the associated file offset. If the image file contains several tile-parts, not recommended, thus dividing the set of packets in not contiguous segments, special markers are included to identify the offset jumps. \subsection{Client manager} The class \hyperlink{classClientManager}{ClientManager} contains the required code to handle a client connection. When a new client connection is established by the server, a new instance of this class is created passing a reference to the application shared information (\hyperlink{classAppInfo}{AppInfo}), a reference of the server configuration information (\hyperlink{classAppConfig} {AppConfig}) and a reference to the Index manager (\hyperlink{classjpeg2000_1_1IndexManager} {jpeg2000::IndexManager}). A new thread is created for this connection which calls the method ``Run'' of the class. The function of the code of the class \hyperlink{classClientManager}{ClientManager} is basically to parse the client requests (with the help of the class \hyperlink{classjpip_1_1Request}{jpip::Request}) and form the appropriate responses, all of them according to the JPIP protocol in HTTP format. It implements a basic channel handling mechanism, as well as the interface with the Index manager, in order to, when a new image file is requested by the client, get the associated index. Although the standard allows to use several channels over the same connection, this implementation does not allow this feature. In practice, the most of the applications do not use more than just one channel per connection, like for example in the case of the viewer kdu\_show, from the Kakadu library, or JHelioviewer. This means that the JPIP concepts of channel and session refer in this implementation to the same thing. However, in the same connection, the client can open and close several channels as many times as required, but considering that only one channel can be opened at the same time. In order to identify the channel opened by the client, a simple integer number is used, which is incremented each time the client opens and closes a channel. The target identifier returned by the server, when a channel is opened, and that is commonly used by the JPIP clients to perform local caching, is the full path of the associated image file. This avoids the coherence problems detected in other server implementations (like in the case of the kdu\_server) when using complex hash values. Taking into account that the child process can be restarted, and the client manager might be started over an existing client connection, a mechanism to find out the data already sent to the client, but without requesting it, has been implemented. Each time all the complete data of a WOI has been sent to the client, a little ``.backup'' file is created in the caching directory with the content of the client cache model. Therefore, when a client manager is started, it checks whether an associated ``.backup'' exists or not, loading its information as the current content of the client cache model if so. The main flow chart of the code of the client manager module can be observed in Fig. \ref{fig:client_manager}. In the processing step of generating a new chunk of data is when the data-bin server module is called. \begin{figure} \centering \resizebox{0.9\textwidth}{!}{ \input{../client_manager} } \caption{Flow chart of the client manager.} \label{fig:client_manager} \end{figure} \subsection{Data-bin server} The code of this module is located at the class \hyperlink{classjpip_1_1DataBinServer} {jpip::DataBinServer}. This module manages the data that is served to a client, having methods to generate chunks and data-bins, as well as it maintains the client cache model. The client cache model is managed with the help of the class \hyperlink{classjpip_1_1CacheModel}{jpip::CacheModel}. This class can be serialized, what make easy saving/loading the ``.backup'' files generated by the client manager. The data-bin server module uses the methods of the class \hyperlink{classjpip_1_1DataBinWriter}{jpip::DataBinWriter} for generating the data-bins that will be sent to the client by the client manager. Once the client manager receives a WOI request from the client, it is passed to the data-bin server, which parses it and prepares the related resources for the data-bin generation. For instance, when the WOI specifies a set of hyperlinked layers within a JPX file, the data-bin server opens the associated files putting them ready for extracting packets. An object of the class \hyperlink{classjpip_1_1WOIComposer} {WOIComposer} is also prepared to explore the packets associated to the WOI specified in the client request. For each WOI request the client manager sends JPIP responses encapsulated in HTTP messages, and using the chunked transfer encoding. The maximum length of each chunk is determined by the value specified within the configuration file. The method ``GenerateChunk'' of the class \hyperlink{classjpip_1_1DataBinServer} {jpip::DataBinServer} is able to fill a memory buffer, usually related to a chunk data, with data-bins, according to the current client cache model and the last passed request. This is the method used by the client manager to generate the responses. The data-bin server generates a new chunk of data-bins considering the data already sent, recorded in the client cache model. Therefore, if the first $N$ bytes of a precinct data-bin has been already sent to the client, in the next chunk generation, these first $N$ bytes of the same precinct are not included. The sequence of data-bins that are included when a new data chunk is generated, calling the ``GenerateChunk'' method, is as follows: \begin{enumerate} \item All the metadatas \item For each codestream: \begin{enumerate} \item Main-header \item Tile-header \end{enumerate} \item For each packet given by the \hyperlink{classjpip_1_1WOIComposer}{WOIComposer}: \begin{enumerate} \item For each codestream: Precinct \end{enumerate} \end{enumerate} Notice that, as it has been commented, the chunk generation and data-bin inclusion is incremental according to the client cache model and the previous sequence. For example, if the metadata of an image file occupies $1$ MByte, and the chunk size is $1$ KB, more than $1000$ chunks would be required to be generated before being able to generate the first chunk with packet data (precinct). \section{Libraries} \label{libraries} The application uses the following libraries: \begin{itemize} \item \textit{Libconfig++}: The libconfig++ library (\href{http://www.hyperrealm.com/libconfig/}{http://www.hyperrealm.com/libconfig/}) is used to read the information of the configuration file of the server. The configuration file accepts C-like comments. \item \textit{Libproc}: The general information about the server process is shown thanks to this library (\href{http://packages.debian.org/sid/libproc-dev/}{http://packages.debian.org/sid/libproc-dev/}). \item \textit{Log4cpp}: This library is in charge of flexible logging to file (\href{http://log4cpp.sourceforge.net/}{http://log4cpp.sourceforge.net/}). \end{itemize} esajpip-0.1~bzr33/doc/doxyfile0000644000175000017500000021061112335423210016250 0ustar mathieumathieu# Doxyfile 1.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "ESA JPIP server" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 0.1 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = __DOC_DIR__ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = YES # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = __SRC_DIR__ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = YES # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = __SRC_DIR__ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.vhd \ *.vhdl # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = YES # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvances is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = header.tex # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES esajpip-0.1~bzr33/doc/client_manager.fig0000644000175000017500000001240512335423210020142 0ustar mathieumathieu#FIG 3.2 Produced by xfig version 3.2.5b Portrait Center Metric A4 100.00 Single -2 1200 2 0 32 #ffffff 6 2340 2610 4770 3960 6 2925 3060 4140 3555 4 1 0 0 0 16 10 0.0000 6 120 735 3533 3197 Is there an\001 4 1 0 0 0 16 10 0.0000 6 150 1155 3533 3364 associate backup\001 4 1 0 0 0 16 10 0.0000 6 120 285 3533 3531 file?\001 -6 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 3555 2610 4770 3285 3555 3960 2340 3285 3555 2610 -6 6 -1125 2790 1350 3780 6 -900 3105 1125 3465 4 1 0 0 0 16 10 0.0000 6 150 1875 114 3240 Load the content, removes\001 4 1 0 0 0 16 10 0.0000 6 150 1995 114 3407 the file and open the channel\001 -6 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 -1125 2790 1350 2790 1350 3780 -1125 3780 -1125 2790 -6 6 3150 7560 3960 7920 4 1 0 0 0 16 10 0.0000 6 120 795 3553 7715 Contains a \001 4 1 0 0 0 16 10 0.0000 6 120 630 3553 7881 ''cclose''?\001 -6 6 3105 9495 3960 9810 4 1 0 0 0 16 10 0.0000 6 120 570 3539 9783 ''cnew''?\001 4 1 0 0 0 16 10 0.0000 6 120 795 3539 9616 Contains a \001 -6 6 3150 11385 4005 11745 4 1 0 0 0 16 10 0.0000 6 120 795 3582 11542 Contains a \001 4 1 0 0 0 16 10 0.0000 6 120 405 3582 11709 ''cid''?\001 -6 6 2790 13050 4365 13365 4 1 0 0 0 16 10 0.0000 6 120 1530 3558 13178 Generate a new chunk\001 4 1 0 0 0 16 10 0.0000 6 120 1305 3558 13345 of data and send it\001 -6 6 2880 14625 4140 14985 4 1 0 0 0 16 10 0.0000 6 120 1245 3517 14747 Is the related WOI\001 4 1 0 0 0 16 10 0.0000 6 150 795 3517 14914 completed?\001 -6 6 6075 9405 7785 9945 4 1 0 0 0 16 10 0.0000 6 120 1380 6940 9568 Creates the channel\001 4 1 0 0 0 16 10 0.0000 6 150 1545 6940 9734 a gets the image index\001 4 1 0 0 0 16 10 0.0000 6 150 1665 6940 9901 from the Index manager\001 -6 6 6030 7515 8055 7875 4 1 0 0 0 16 10 0.0000 6 150 1995 7034 7676 Closes the specified channel,\001 4 1 0 0 0 16 10 0.0000 6 150 1965 7034 7843 and removes the backup file \001 -6 6 2634 16233 4389 16550 4 1 0 0 0 16 10 0.0000 6 120 1500 3511 16353 Store the client cache\001 4 1 0 0 0 16 10 0.0000 6 150 1755 3511 16520 model within a backup file\001 -6 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 2745 4534 4334 4534 4334 5220 2745 5220 2745 4534 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3555 3960 3555 4545 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3555 5220 3555 5805 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 2731 5794 4320 5794 4320 6480 2731 6480 2731 5794 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3555 6480 3555 7065 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 3554 7081 4769 7756 3554 8431 2339 7756 3554 7081 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3555 8415 3555 9000 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 3541 8993 4756 9668 3541 10343 2326 9668 3541 8993 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3555 10350 3555 10935 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 3556 10919 4771 11594 3556 12269 2341 11594 3556 10919 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3555 2025 3555 2610 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 2731 1339 4320 1339 4320 2025 2731 2025 2731 1339 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 2340 3285 1350 3285 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3 2 1 3.00 120.00 120.00 90 3780 90 4905 2790 4905 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3555 12285 3555 12870 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 2610 12870 4545 12870 4545 13545 2610 13545 2610 12870 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3510 13545 3510 14130 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 3510 14130 4725 14805 3510 15480 2295 14805 3510 14130 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3510 15480 3510 16065 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 2430 16065 4590 16065 4590 16740 2430 16740 2430 16065 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2 2 1 3.00 120.00 120.00 5760 9675 4770 9675 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 5760 7245 8235 7245 8235 8235 5760 8235 5760 7245 2 3 0 1 0 0 0 0 -1 0.000 0 0 0 0 0 5 5760 9180 8235 9180 8235 10170 5760 10170 5760 9180 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2 2 1 3.00 120.00 120.00 5760 7740 4770 7740 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 4 2 1 3.00 120.00 120.00 8280 7740 9180 7740 9180 4815 4365 4815 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 8235 9675 9180 9675 9180 7740 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 4725 14805 9180 14805 9180 9675 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4 3510 16740 3510 17370 9180 17370 9180 14805 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 2 1 3.00 120.00 120.00 3510 16785 3510 17370 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 4725 11610 9180 11610 9180 6480 4 1 0 0 0 16 10 0.0000 6 150 1110 3510 4950 Wait for request\001 4 1 0 0 0 16 10 0.0000 6 150 1215 3555 6210 Parse the request\001 4 1 0 0 0 16 10 0.0000 6 150 390 3555 1710 Begin\001 4 1 0 0 0 16 10 0.0000 6 120 225 2025 3150 yes\001 4 1 0 0 0 16 10 0.0000 6 90 180 3735 4185 no\001 4 1 0 0 0 16 10 0.0000 6 120 225 5175 7605 yes\001 4 1 0 0 0 16 10 0.0000 6 90 180 3780 8640 no\001 4 1 0 0 0 16 10 0.0000 6 120 225 5175 9540 yes\001 4 1 0 0 0 16 10 0.0000 6 90 180 3735 10575 no\001 4 1 0 0 0 16 10 0.0000 6 120 225 3780 12465 yes\001 4 1 0 0 0 16 10 0.0000 6 120 225 3735 15705 yes\001 4 1 0 0 0 16 10 0.0000 6 90 180 5130 14715 no\001 4 1 0 0 0 16 10 0.0000 6 90 180 5130 11520 no\001 esajpip-0.1~bzr33/doc/Makefile0000644000175000017500000000122312335423210016137 0ustar mathieumathieuSHELL=/bin/bash FIGS = jpip_fig \ partition \ codestream \ architecture \ client_manager %.eps %.tex: %.fig fig2dev -L pstex $*.fig > $*.eps (fig2dev -L pstex_t -p $* $< | sed 's/includegraphics{/includegraphics{..\//g') > $*.tex %.pdf: %.eps epstopdf $*.eps doc: $(FIGS:%=%.pdf) documentation clean: rm -rf *.pdf latex html doxyfile.ok rm -rf $(FIGS:%=%.pdf) $(FIGS:%=%.tex) $(FIGS:%=%.eps) documentation: n=$$(cd ..; pwd) && \ cat doxyfile | \ sed -e "s:__SRC_DIR__:$$n/src/:g" | \ sed -e "s:__DOC_DIR__:$$n/doc/:g" \ > doxyfile.ok && \ doxygen doxyfile.ok && \ make -C latex && \ mv latex/refman.pdf . esajpip-0.1~bzr33/doc/partition.fig0000644000175000017500000001306012335423210017201 0ustar mathieumathieu#FIG 3.2 Produced by xfig version 3.2.5 Landscape Center Metric A4 100.00 Single -2 1200 2 0 32 #ff746e 0 33 #000000 0 34 #cf0000 0 35 #009b00 0 36 #0000cf 0 37 #b0b0b0 6 5670 6660 6840 7830 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 5985 6975 6255 6975 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 5985 6930 5985 7245 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 6255 7245 6795 7245 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 6255 7245 6255 7785 2 2 0 2 35 7 45 -1 -1 4.500 0 0 -1 0 0 5 5715 6705 5985 6705 5985 6975 5715 6975 5715 6705 2 2 0 2 35 7 45 -1 -1 4.500 0 0 -1 0 0 5 5715 6705 6255 6705 6255 7245 5715 7245 5715 6705 2 2 0 2 35 7 45 -1 -1 4.500 0 0 -1 0 0 5 5715 6705 6795 6705 6795 7785 5715 7785 5715 6705 2 2 2 0 0 37 52 -1 20 3.000 0 0 -1 0 0 5 5895 7425 6165 7425 6165 7695 5895 7695 5895 7425 2 2 1 0 0 37 52 -1 20 2.000 0 0 -1 0 0 5 6435 7425 6705 7425 6705 7695 6435 7695 6435 7425 2 2 1 0 0 37 52 -1 20 2.000 0 0 -1 0 0 5 6435 6885 6705 6885 6705 7155 6435 7155 6435 6885 -6 6 3780 5580 4680 6840 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 4410 6570 4410 6120 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 4230 6705 4230 6120 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 4050 6840 4050 6120 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 4050 6120 4590 6120 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 4590 6435 4590 6120 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 4320 6120 4320 5760 4 0 0 52 -1 0 12 0.0000 6 150 900 3780 5715 components\001 -6 2 1 1 1 0 15 52 -1 20 4.000 0 0 -1 0 0 2 720 7110 3015 7110 2 1 1 1 0 15 52 -1 -1 4.000 0 0 -1 0 0 2 2340 6030 2340 8190 2 1 1 1 0 15 52 -1 -1 4.000 0 0 -1 0 0 2 2745 6030 2745 8190 2 1 1 1 0 7 52 -1 -1 4.000 0 0 -1 0 0 2 1935 6030 1935 8190 2 1 1 1 0 7 52 -1 -1 4.000 0 0 -1 0 0 2 1530 6030 1530 8190 2 1 1 1 0 7 52 -1 -1 4.000 0 0 -1 0 0 2 1125 6030 1125 8190 2 1 1 1 0 7 52 -1 -1 4.000 0 0 -1 0 0 2 720 6390 3015 6390 2 1 1 1 0 7 52 -1 -1 4.000 0 0 -1 0 0 2 720 6750 3015 6750 2 1 1 1 0 15 52 -1 -1 4.000 0 0 -1 0 0 2 720 7470 3015 7470 2 1 1 1 0 7 52 -1 -1 4.000 0 0 -1 0 0 2 720 7830 3015 7830 2 2 0 2 0 11 56 -1 20 0.000 0 0 -1 0 0 5 900 6255 2880 6255 2880 8010 900 8010 900 6255 2 4 0 1 0 7 52 -1 -1 0.000 0 0 2 0 0 5 3015 8190 720 8190 720 6030 3015 6030 3015 8190 2 2 0 0 0 37 54 -1 20 0.000 0 0 -1 0 0 5 2340 7110 2745 7110 2745 7470 2340 7470 2340 7110 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 2745 7110 3510 6840 2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2 2745 7470 3510 7920 2 2 0 2 34 7 51 -1 20 0.000 0 0 -1 0 0 5 3546 6831 4635 6831 4635 7920 3546 7920 3546 6831 2 2 0 2 1 7 53 -1 20 0.000 0 0 -1 0 0 5 3804 6570 4905 6570 4905 7659 3804 7659 3804 6570 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 4770 7785 5715 7785 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 4770 6705 5715 6705 2 2 1 1 0 7 54 -1 20 4.000 0 0 -1 0 0 5 3951 6435 5040 6435 5040 7524 3951 7524 3951 6435 2 2 0 2 35 7 52 -1 20 0.000 0 0 -1 0 0 5 3657 6705 4770 6705 4770 7794 3657 7794 3657 6705 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 6705 6885 7650 6705 2 1 2 1 0 7 50 -1 20 3.000 0 0 -1 0 0 2 6705 7155 7605 7605 2 1 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 2 5805 6435 6570 6435 2 1 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 2 6120 6705 6120 6435 2 1 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 2 5805 6705 5805 6435 2 1 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 2 6570 6705 6570 6435 2 2 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 5 8100 6930 8325 6930 8325 7155 8100 7155 8100 6930 2 2 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 5 8325 6705 8550 6705 8550 6930 8325 6930 8325 6705 2 2 2 1 0 0 53 -1 -1 3.000 0 0 -1 0 0 5 7650 7155 7875 7155 7875 7380 7650 7380 7650 7155 2 2 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 5 7650 6930 7875 6930 7875 7155 7650 7155 7650 6930 2 2 2 1 0 0 53 -1 -1 3.000 0 0 -1 0 0 5 8325 7155 8550 7155 8550 7380 8325 7380 8325 7155 2 2 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 5 7875 7155 8100 7155 8100 7380 7875 7380 7875 7155 2 2 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 5 8100 7155 8325 7155 8325 7380 8100 7380 8100 7155 2 2 2 1 0 0 53 -1 -1 3.000 0 0 -1 0 0 5 8100 6705 8325 6705 8325 6930 8100 6930 8100 6705 2 2 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 5 7650 6705 7875 6705 7875 6930 7650 6930 7650 6705 2 2 2 1 0 0 53 -1 -1 3.000 0 0 -1 0 0 5 7650 7380 7875 7380 7875 7605 7650 7605 7650 7380 2 2 2 1 0 0 53 -1 -1 3.000 0 0 -1 0 0 5 7875 7380 8100 7380 8100 7605 7875 7605 7875 7380 2 2 2 1 0 0 53 -1 -1 3.000 0 0 -1 0 0 5 8100 7380 8325 7380 8325 7605 8100 7605 8100 7380 2 2 2 1 0 0 53 -1 -1 3.000 0 0 -1 0 0 5 8325 7380 8550 7380 8550 7605 8325 7605 8325 7380 2 2 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 5 7875 6930 8100 6930 8100 7155 7875 7155 7875 6930 2 2 2 1 0 0 52 -1 -1 3.000 0 0 -1 0 0 5 7875 6705 8100 6705 8100 6930 7875 6930 7875 6705 2 2 2 0 0 37 54 -1 20 3.000 0 0 -1 0 0 5 7875 6705 8100 6705 8100 6930 7875 6930 7875 6705 2 1 2 1 0 0 52 -1 -1 3.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 6210 6435 6210 6030 2 1 2 1 0 0 45 -1 -1 3.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 8010 6795 8010 6165 2 1 2 1 0 7 52 -1 20 3.000 0 0 -1 0 1 2 1 1 1.00 60.00 120.00 2115 5625 2115 6255 2 2 2 1 0 0 53 -1 -1 3.000 0 0 -1 0 0 5 8325 6930 8550 6930 8550 7155 8325 7155 8325 6930 2 2 0 1 35 0 45 -1 -1 4.500 0 0 -1 0 0 5 7650 6705 8550 6705 8550 7605 7650 7605 7650 6705 4 0 0 52 -1 0 12 0.0000 6 90 540 720 8370 canvas\001 4 0 0 52 -1 0 12 0.0000 6 150 450 1845 5580 image\001 4 0 0 52 -1 0 12 0.0000 6 135 360 3960 8145 tile\001 4 0 0 52 -1 0 12 0.0000 6 150 720 7785 7830 precinct\001 4 0 0 52 -1 0 12 0.0000 6 165 1260 5625 8010 tile-component\001 4 0 0 52 -1 0 12 0.0000 6 135 990 5715 5985 resolutions\001 4 0 0 52 -1 0 12 0.0000 6 135 900 7605 6120 code-block\001 esajpip-0.1~bzr33/doc/jpeg2000.tex0000644000175000017500000003527512335423210016466 0ustar mathieumathieuPart 1 of the \href{http://www.jpeg.org/jpeg2000/}{JPEG2000} standard describes a core compression system that is based on the dyadic \href{http://en.wikipedia.org/wiki/Discrete_wavelet_transform} {DWT (Discrete Wavelet Transform)} and the EBCOT (Embedded Block Coding with Optimal Truncation). Some features of this compression system are high compression ratios, error-resilience, lossless and lossy compression, random access to the compressed stream, resolution and quality scalability, and support for multiple components. These characteristics make it ideal for the coding and retrieving of large remote images. \subsection{Data partitions} The JPEG2000 standard defines a wide variety of partitions for the image data, with the aim of exploiting at the maximum the offered scalability. All of these partitions allow an efficient manipulation of the image, or a part of it. Fig. \ref{fig:partitions} shows a graphical example of the main partitions. \begin{figure}[!b] \begin{center} \resizebox{0.95\textwidth}{!}{\input{../partition}} \end{center} \caption{Data partition defined by the JPEG2000 standard.} \label{fig:partitions} \end{figure} In order to understand the concept of each partition defined in the JPEG2000 standard, it is necessary to clarify the concept of canvas. The canvas is a bidimensional drawing zone where all the partitions are mapped to form the related image. Hereinafter, all the used coordinates are in relation to a canvas, which size, width ($I_{2}$) and height ($I_{1}$), corresponds to the total size of the associated image. Each partition is located and mapped over the canvas in a specific way. An image is composed by one or more components. In the most of the cases the images have only three components: red, green and blue (RGB), with a size equals to the canvas. The JPEG2000 standard allows to divide an image into smaller rectangular regions called tiles. Each tile is compressed independently in relation to the rest, hence the compression parameters can be different among them. By default there is always one tile as minimum, which equals to the whole image. One of the possible applications of the tile partitioning is its use with images that contain different elements and visually separated, like text, graphics or photographic materials. When this does not occur, and the images are continuous and homogeneous, the tiling is not recommended because it produces artifacts in the borders of the tiles, causing a mosaic effect. Moreover, the size of a compressed image is larger when the tiles are used. The DWT transform and all the quantification/coding stages are applied independently to each tile-component. A tile-component, of a tile $t$ and a component $c$, is defined by a bidimensional zone limited by $t$ taking into account the zone occupied by $c$. This means that, if an image has only one tile, with three color components, there are three tile-components, which are compressed independently. For each tile-component, identified by the tile $t$ and the component $c$, there are a total of $D_{t,c} + 1$ resolutions, where $D_{t,c}$ is the number of DWT stages applied. The $r$-nth resolution level of a compressed tile-component is obtained after applying $r$ times the inverse DWT transform. The $r$ value is in the range of $0 \leq r \leq D_{t,c}$. Each tile-component, after being applied the DWT, is divided into code-blocks, that are coded independently. In each resolution $r$ of each tile-component $(t,c)$, the code-blocks are grouped in precincts. This partition is defined by the height, $P_{1}^{t,c,r}$, and the width, $P_{2}^{t,c,r}$, of each precinct. The number of precincts in vertical, $N_{1}^{P,t,c,r}$, as well as in horizontal, $N_{2}^{P,t,c,r}$ are given by the following expression: \begin{equation*} N_{i}^{P,t,c,r} = \left\lceil \frac{I_{i}}{2^{D_{t,c}-r}P_{i}^{t,c,r}} \right\rceil \end{equation*} Code-blocks refer to the wavelet coefficients generated by the DWT transform, thus rectangular regions within the wavelet domain. However, precincts refer to rectangular regions within the image domain. The spatial scalability offered by the standard is carried out with the precincts. The packet is the fundamental unit for the organization of the compressed bit-stream of an image. Each precinct contributes to the bit-stream as many packets as quality layers there are. The compressed data of each code-block is divided in different segments called quality layers. All the code-blocks of all the precincts of the same tile are divided into the same number of quality layers, although the length of the quality layers between code-blocks can be different (the length can be even zero). For a certain layer $l$, the set of all the layer $l$ of all the code-blocks related to a precinct form a packet. In order to decode a certain region of an image it is necessary decode all the packets related to that region. In the server code, the class \hyperlink{classjpip_1_1WOIComposer}{jpip::WOIComposer} allows to know, for a given region of interest, hereinafter called WOI (Window Of Interest), all the required packets to decode it. A packet $\zeta_{t,c,r,p,l}$ is identified by the tile $t$, the component $c$, the resolution $r$, the precinct $p$ (in precinct coordinates) and the quality layer $l$. In the server code, the class \hyperlink{classjpeg2000_1_1Packet}{jpeg2000::Packet} is used to identify a packet. \subsection{Code-stream organization} Part 1 of the JPEG2000 standard defines a basic structure for organizing the image compressed data into code-streams. A code-stream includes all the packets generated by a compression process of an image plus a set of markers, that are used for signaling certain parts, as well as for including information necessary for the decompression. The code-stream is itself a simple file format for JPEG2000 image. Any standard decompressor must be able to understand a code-stream stored within a file. This basic format is also called raw, and its most used extension is ``.J2C''. The markers have an unique identifier, that consists of an unsigned integer of $16$ bits. These markers can be found alone, that is, only the identifier, or accompanied by additional information, receiving in this case the name of marker segment. The marker segment has, after the identifier, another unsigned integer of $16$ bits with the length of the included data, including as well the two bytes of this integer, but without counting the two bytes of the identifier. The code-stream always begins with the SOC (Start Of Code-stream) marker, which does not include any additional information. After this marker a set of markers called ``main header'' begins. After the SOC marker there is always a SIZ marker, with global information necessary for decompressing the data, e.g. the image size, the tile size, the anchor point of the tiles, the number of components, the sub-sampling factors, etc. There are another two markers that are mandatory in the main header: COD, with information related to the coding of the image, like the number of layers, number of DWT stages, the size of the code-blocks, the progression, etc.; and QCD, which contains the quantization parameters. These two markers can be stored in any position within the main header. The rest of the code-stream, until the EOC (End Of Code-stream), located just at the end of it, is organized as it is shown in Fig. \ref{fig:code-stream}. For each image tile, there is a set of data. This data is divided into one or more tile-parts. Each tile-part is composed by a header and a set of packets. The header of the first tile-part is the main header of the tile. The header of each tile-part begins with the SOT (Start Of Tile) marker and ends with the SOD (Start Of Data) marker, starting then the related sequence of packets, according to the last COD or POC marker. The main header ends when the first SOT is found. \begin{figure}[!t] \begin{center} \resizebox{0.65\textwidth}{!}{\input{../codestream}} \end{center} \caption{Code-stream organization.} \label{fig:code-stream} \end{figure} In order to permit a random access to the data of a code-stream, that by default is not feasible, JPEG2000 offers the possibility of including the TLM, PLM and/or PLT markers. The TLM and PLM markers are included within the main header, whilst the PLT marker goes in the header of a tile or tile-part. The goal of the TLM marker is to store the length of each tile-part that appear within the code-stream. This length includes the header as well as the set of packets, so for knowing where is the beginning of the data it is necessary to analyze firstly the header. The PLM marker stores the length of each packet of each tile-part of the code-stream. Each packet of the code-stream has a certain length, that can not be known a priori. Therefore including this marker facilitates a random access of the packets. The PLT marker has the same function as the PLM marker, but at the level of tile-part, thus it stores the length of all the packets of the belonging tile-part. This marker is commonly most used than PLM. The PLM and PLT markers produces an increase of the code-stream length, although the way of coding the packet lengths helps to avoid an excessive overhead: a length $L$ of a certain packet, that can be represented with $B_{L}$ bits, is stored coded with $\left \lceil \frac{B_{L}}{7} \right \rceil$ bytes. For a length $L$ is generated a sequence of bytes where only the less significant $7$ bits are used. The most significant bit of each byte indicates if the belonging byte is ($1$) or not ($0$) the last one of the sequence. This way of numeric encoding is widely used in Part 9 of the standard, specially with the JPIP protocol. With this protocol, to each variable sequence of bytes that represents a number encoded in this way is called VBAS (Variable Byte-Aligned Segment). The class \hyperlink{classjpip_1_1DataBinWriter}{jpip::DataBinWriter}, within the server code, contains methods to generate VBAS coded values. \subsection{Progressions} \label{sec:progresiones} The packets generated by the JPEG2000 compression process are neither independent nor self-contained. Having a certain packet, it is not possible to figure out to which part of the related image it belongs without additional information. The length of the packet can not be determined before being decoded, and many packets can not be decoded without decoding other packets before. This is why it is necessary to include markers like TLM, PLT or PLM, previously commented, in order to allow a random access without decoding. The packets of each tile-part appear according the progression specified by the last COD or POC marker read, before the SOD marker. Part 1 of the JPEG2000 standard defines 5 possible kinds of progressions for ordering the packets within a tile or tile-part. Each progression is identified by means of a combination of four letters: ``L'' for quality layer, ``R'' for resolution level, ``C'' for component and ``P'' for precinct. Each letter identifies the partition of the progression. Hence for the LRCP progression, for example, the packets would be included as follows:\\ \\for each layer $l$\\ \hspace*{1cm} for each resolution $r$\\ \hspace*{2cm} for each component $c$\\ \hspace*{3cm} for each precinct $p$\\ \hspace*{4cm} include the packet $\zeta_{t,c,r,p,l}$\\ The different progressions allowed by the standard are: LRCP, RLCP, RPCL, PCRL and CPRL. To choose a progression or another depends on the application to develop, and how the packet must to be decoded. For example, if the packets are going to be accessed randomly, but as minimum disk accesses as possible are required, RPCL would be the ideal progression in this case. In the case of image transmission, the packets must also follow a specific order or progression when they are transmitted. When an image is transmitted from a server to a client, the most desired goal is to allow the client to be able to show reconstructions of the image with a quality that is increased as the data is received. The quality of the reconstruction must be always the maximum possible according to the received data. Under this criteria, the LRCP progression can be confirmed as the best one, and it is the progression used by the class \hyperlink{classjpip_1_1WOIComposer}{jpip::WOIComposer}. \subsection{File formats} Although the code-stream is completely functional as a basic file format, it does not allow to include additional information that could be necessary in certain applications, e.g. meta-data, copyright information, or color palettes. By means of the COM marker auxiliary information can be included within a code-stream, but it is not classified nor organized in a standard way. Part 1 of the standard also defines a file format based on ``boxes'' that allows to include, for example, in the same file, several code-streams and diverse information correctly identified. These files usually have the extension ``.JP2'', extension also used for calling this kind of files. The JP2 files are easily extensible. A basic structure of box is defined, which can contains any kind of information. Each box is unequivocally classified by means of a $4$-bytes identifier. A file can contain several boxes with the same identifier. The standard proposes an initial set of boxes, that may be extended according to specific requirements. In fact, the JP2 format is the base of the rest of formats and extensions defined in the rest of parts of the standard. Each box has a header of $8$ bytes. The first $4$ bytes, $L$, form an unsigned integer with the length in bytes of the content of the next $4$ bytes, $T$, contain the identifier of the kind of box. This identifier is commonly treated like a string of $4$ ASCII characters. The value of $L$ includes the header, hence the real length of the content of the box is $L - 8$. $L$ can have any value bigger or equal to $8$, but also $1$ or $0$. If $L = 1$ the length of the content of the box is coded as an unsigned integer of $8$ bytes, $X$, located after $T$. In this case the header occupies $16$ bytes and the length of the content is then $X - 16$. If $L = 0$ the length of the box content is undefined, being possible only for the last box of the image file. Boxes can contain another boxes inside. It is possible to know whether a box contains or not sub-boxes depending on the value of $T$. If a box contains sub-boxes, it only can contain sub-boxes, so it can not combine sub-boxes with other data. Within the server code, the class \hyperlink{classjpeg2000_1_1FileManager} {jpeg2000::FileManager} contains all the necessary code to read and parse JPEG2000 image files, from simple raw J2C files to complex JPX ones with hyperlinks. When this class parses an image file, extract the associated index information and stores it in an object of the class \hyperlink{classjpeg2000_1_1ImageInfo}{jpeg2000::ImageInfo}. esajpip-0.1~bzr33/doc/header.tex0000644000175000017500000000251512335423210016456 0ustar mathieumathieu\documentclass[a4paper]{book} \usepackage{a4wide} \usepackage{makeidx} \usepackage{graphicx} \usepackage{multicol} \usepackage{float} \usepackage{listings} \usepackage{color} \usepackage{textcomp} \usepackage{alltt} \usepackage{times} \usepackage{ifpdf} \usepackage{amsmath} \ifpdf \usepackage[pdftex, pagebackref=true, colorlinks=true, linkcolor=blue, unicode ]{hyperref} \else \usepackage[ps2pdf, pagebackref=true, colorlinks=true, linkcolor=blue, unicode ]{hyperref} \usepackage{pspicture} \fi \usepackage[utf8]{inputenc} \usepackage{../doxygen} \lstset{language=C++,inputencoding=utf8, basicstyle=\footnotesize,breaklines=true, breakatwhitespace=true,tabsize=8,numbers=left} \makeindex \setcounter{tocdepth}{3} \renewcommand{\footrulewidth}{0.4pt} \begin{document} \hypersetup{pageanchor=false} \begin{titlepage} \vspace*{7cm} \begin{center} {\Huge ESA JPIP server}\\ {\large Version \input{../../VERSION}}\\ \vspace*{1cm} {\Large Documentation}\\ \vspace*{0.5cm} {\today}\\ \end{center} \end{titlepage} \clearemptydoublepage \pagenumbering{roman} \tableofcontents \clearemptydoublepage \pagenumbering{arabic} \hypersetup{pageanchor=true} \part{Application} \input{../guide.tex} \part{Source code} \label{sourcecode} esajpip-0.1~bzr33/.cproject0000644000175000017500000003736612335423210015565 0ustar mathieumathieu esajpip-0.1~bzr33/src/0000755000175000017500000000000012335423210014523 5ustar mathieumathieuesajpip-0.1~bzr33/src/packet_information.cc0000644000175000017500000001004112335423210020702 0ustar mathieumathieu#include "trace.h" #include "app_config.h" #include "jpip/woi_composer.h" #include "jpeg2000/index_manager.h" using namespace std; using namespace jpip; using namespace jpeg2000; struct ui { template static void read(T& v, T mn, T mx) { do { cin >> v; } while ((v < mn) || (v > mx)); } }; int main(void) { AppConfig cfg; if (cfg.Load("server.cfg")) cout << endl << cfg << endl; else { cerr << "The configuration file can not be read" << endl; return -1; } string name_image_file; if (!File::Exists(cfg.caching_folder().c_str())) cerr << "The cache folder does not exist" << endl; IndexManager im; im.Init(cfg.images_folder(), cfg.caching_folder()); ImageIndex::Ptr it_node; int option; do { cout << endl << "MENU:" << endl << "-----" << endl << "1) Open image file" << endl << "2) Close image file" << endl << "3) Get WOI packets from image file" << endl << "4) Image file list" << endl << "5) Exit" << endl << endl << "Option: "; ui::read(option, 1, 5); switch (option) { case 1: cout << "Name image file (type 'exit' to finish): "; cin >> name_image_file; while (name_image_file.compare("exit") != 0) { if (im.OpenImage(name_image_file, &it_node)) cout << "Image file loaded..." << endl; else cout << "Image file not loaded..." << endl; cout << "Name image file (type 'exit' to finish): "; cin >> name_image_file; } break; case 2: if (im.GetSize() <= 0) cout << "Image list is empty!" << endl; { if (im.CloseImage(it_node)) cout << "Image file closed." << endl; else cout << "Image file not closed!" << endl; } break; case 3: if (im.GetSize() <= 0) cout << "Image list is empty!" << endl; { int wx, wy, ww, wh, wr, ind_codestream; CodingParameters cp = *it_node->GetCodingParameters(); cout << "Number codestream [0-" << (it_node->GetNumCodestreams() - 1) << "]: "; ui::read(ind_codestream, 0, (int)it_node->GetNumCodestreams() - 1); cout << "Resolution [0-" << cp.num_levels << "]: "; ui::read(wr, 0, cp.num_levels); int max_x = ceil((double)cp.size.x / (1L << (cp.num_levels - wr))) - 1; cout << "Coord. X [0-" << max_x << "]: "; ui::read(wx, 0, max_x); int max_y = ceil((double)cp.size.y / (1L << (cp.num_levels - wr))) - 1; cout << "Coord. Y [0-" << max_y << "]: "; ui::read(wy, 0, max_y); int max_width = ceil((double)cp.size.x / (1L << (cp.num_levels - wr))) - wx; cout << "Width [0-" << max_width << "]: "; ui::read(ww, 0, max_width); int max_height = ceil((double)cp.size.y / (1L << (cp.num_levels - wr))) - wy; cout << "Height [0-" << max_height << "]: "; ui::read(wh, 0, max_height); WOIComposer woi_composer; WOI woi(Point(wx, wy), Size(wh, ww), wr); cout << woi << endl; woi_composer.Reset(woi, it_node->GetCodingParameters()); cout << "ID\tL\tR\tC\tPY\tPX\tOFFSET:LENGTH" << endl; cout << string(60, '-') << endl; it_node->ReadLock(Range(0, 0)); Packet packet; while (woi_composer.GetNextPacket(&packet)) cout << it_node->GetCodingParameters()->GetPrecinctDataBinId(packet) << "\t" << packet << "\t" << it_node->GetPacket(ind_codestream, packet) << endl; cout << string(60, '-') << endl; it_node->ReadUnlock(Range(0, 0)); } break; case 4: int i = 0; cout << endl; for(ImageIndex::Ptr it = im.GetBegin(); it != im.GetEnd(); ++it) { cout << "Node " << i++ << ":" << endl << string(60, '-') << endl << *it << endl << string(60, '-') << endl << endl; } break; } } while (option != 5); return 0; } esajpip-0.1~bzr33/src/args_parser.h0000644000175000017500000000151512335423210017206 0ustar mathieumathieu#ifndef _ARGS_PARSER_H_ #define _ARGS_PARSER_H_ #include "app_info.h" #include "app_config.h" /** * Class that allows to parse and handle the application * command line parameters. */ class ArgsParser { private: AppConfig& cfg; ///< Application configuration AppInfo& app_info; ///< Application run-time information public: /** * Initializes the object. * @param _cfg Application configuration. * @param _app_info Application run-time information. */ ArgsParser(AppConfig& _cfg, AppInfo& _app_info) : cfg(_cfg), app_info(_app_info) { } /** * Parses and handles the application command line parameters. * @param argc Number of parameters. * @param argv Command line parameters. * @return true if successful. */ bool Parse(int argc, char **argv); }; #endif /* _ARGS_PARSER_H_ */ esajpip-0.1~bzr33/src/base.cc0000644000175000017500000000002212335423210015736 0ustar mathieumathieu#include "base.h" esajpip-0.1~bzr33/src/client_info.h0000644000175000017500000000250312335423210017165 0ustar mathieumathieu#ifndef _CLIENT_INFO_H_ #define _CLIENT_INFO_H_ #include /** * Contains information of a connected client. */ class ClientInfo { private: int sock_; ///< Client socket int base_id_; ///< Base identifier time_t tm_start; ///< When the connection started int father_sock_; ///< Father socket long bytes_sent_; ///< Total bytes sent public: /** * Initializes the object. * @param base_id Base identifier. * @param sock Client socket. * @param father_sock Father socket. */ ClientInfo(int base_id, int sock, int father_sock) { sock_ = sock; bytes_sent_ = 0; base_id_ = base_id; tm_start = ::time(NULL); father_sock_ = father_sock; } /** * Returns the client socket. */ int sock() const { return sock_; } /** * Returns the base identifier. */ int base_id() const { return base_id_; } /** * Returns the father socket. */ int father_sock() const { return father_sock_; } /** * Returns the total bytes sent. */ long bytes_sent() const { return bytes_sent_; } /** * Returns the time spent from the starting * of the connection. */ long time() const { time_t now = ::time(NULL); return (long)(tm_start - now); } virtual ~ClientInfo() { } }; #endif /* _CLIENT_INFO_H_ */ esajpip-0.1~bzr33/src/app_info.h0000644000175000017500000001017712335423210016475 0ustar mathieumathieu#ifndef _APP_INFO_H_ #define _APP_INFO_H_ #include #include #include #ifndef _NO_READPROC #include #endif using namespace std; /** * Contains the run-time information of the application. * This class can be printed. */ class AppInfo { private: /** * Contains the data block that is maintained in * shared memory. */ struct Data { int father_pid; ///< PID of the father process int child_pid; ///< PID of the child process int num_connections; ///< Number of open connections int child_iterations; ///< Number of iterations done by the child /** * Clears the values. */ void Reset() { father_pid = 0; child_pid = 0; num_connections = 0; child_iterations = 0; } }; int shmid; ///< Identifier of the shared memory block int lock_file; ///< Lock file Data *data_ptr; ///< Pointer to the shared memory block bool is_running_; ///< true if the application is running int num_threads_; ///< Number of active threads double child_memory_; ///< Memory used by the child process unsigned long time_; ///< Time spent by the father double father_memory_; ///< Memory used by the father process double available_memory_; ///< Available memory in the system unsigned long child_time_; ///< Time spend by the child /** * Returns a specific field of /proc//stat as a string. */ string GetProcStat_(int pid, int field) const; /** * Returns a specific field of /proc//stat as a defined type. */ template TYPE GetProcStat(int pid, int field) const { TYPE val; string str = GetProcStat_(pid, field); istringstream(str) >> val; return val; } public: /** * Initializes the object. */ AppInfo() { shmid = -1; lock_file = -1; child_memory_ = 0; father_memory_ = 0; is_running_ = false; available_memory_ = 0; child_time_ = 0; data_ptr = NULL; num_threads_ = 0; time_ = 0; } /** * Initializes the object and the handling of the application * run-time information. * @return true if successful. */ bool Init(); /** * Returns true if the application is running. */ bool is_running() const { return is_running_; } friend ostream& operator <<(ostream &out, const AppInfo &app) { out << "Status: " << (app.is_running() ? "running" : "stopped") << endl; out << "Available memory: " << setiosflags(ios::fixed) << setprecision(2) << app.available_memory() << " MB" << endl; if(app.is_running()) { out << "Father PID: " << app->father_pid << endl; out << "Child PID: " << app->child_pid << endl; out << "Child threads: " << app.num_threads() << endl; out << "Child iterations: " << app->child_iterations << endl; out << "Num. connections: " << app->num_connections << endl; out << "Father used memory: " << setiosflags(ios::fixed) << setprecision(2) << app.father_memory() << " MB" << endl; out << "Child used memory: " << setiosflags(ios::fixed) << setprecision(2) << app.child_memory() << " MB" << endl; } return out; } /** * Updates the run-time information of the application. */ AppInfo& Update(); /** * Returns the available memory of the system. */ double available_memory() const { return available_memory_; } /** * Returns the memory used by the father process. */ double father_memory() const { return father_memory_; } /** * Returns the memory used by the child process. */ double child_memory() const { return child_memory_; } /** * Returns the number of active threads. */ int num_threads() const { return num_threads_; } /** * Returns the time spent by the child process. */ unsigned long child_time() const { return child_time_; } /** * Returns the time spent by the father process. */ unsigned long time() const { return time_; } Data *operator->() const { assert(data_ptr); return data_ptr; } ~AppInfo(); }; #endif /* _APP_INFO_H_ */ esajpip-0.1~bzr33/src/jpeg2000/0000755000175000017500000000000012335423210015752 5ustar mathieumathieuesajpip-0.1~bzr33/src/jpeg2000/codestream_index.h0000644000175000017500000000411112335423210021435 0ustar mathieumathieu#ifndef _JPEG2000_CODESTREAM_INDEX_H_ #define _JPEG2000_CODESTREAM_INDEX_H_ #include #include "base.h" #include "data/file_segment.h" namespace jpeg2000 { using namespace data; /** * Class used for indexing the information of a JPEG2000 * codestream. The indexed information is the segment of * the main header, the contiguous segments of packets * (usually the data of each tile-part) and the segments * of the existing PLT markers. This class can be printed * and serialized. * * @see data::FileSegment */ class CodestreamIndex { public: FileSegment header; ///< Main header segment vector packets; ///< Tile-part packets segments vector PLT_markers; ///< PLT markers segments /** * Empty constructor. */ CodestreamIndex() { } /** * Copy constructor. */ CodestreamIndex(const CodestreamIndex& index) { *this = index; } /** * Clears the information. */ void Clear() { packets.clear(); PLT_markers.clear(); } /** * Copy assignment. */ const CodestreamIndex& operator=(const CodestreamIndex& index) { header = index.header; base::copy(packets, index.packets); base::copy(PLT_markers, index.PLT_markers); return *this; } template T& SerializeWith(T& stream) { return (stream & header & packets & PLT_markers); } friend ostream& operator << (ostream &out, const CodestreamIndex &index) { out << "Header: " << index.header << endl; out << "Packets: "; for(vector::const_iterator i = index.packets.begin(); i != index.packets.end(); i++) out << *i << " "; out << endl << "PLT-markers: "; for(vector::const_iterator i = index.PLT_markers.begin(); i != index.PLT_markers.end(); i++) out << *i << " "; out << endl; return out; } virtual ~CodestreamIndex() { } }; } #endif /* _JPEG2000_CODESTREAM_INDEX_H_ */ esajpip-0.1~bzr33/src/jpeg2000/index_manager.cc0000644000175000017500000001052012335423210021060 0ustar mathieumathieu//#define SHOW_TRACES #include #include "trace.h" #include "index_manager.h" namespace jpeg2000 { using namespace std; bool IndexManager::OpenImage(string& path_image_file, ImageIndex::Ptr *image_index) { bool res = false; if(mutex.Wait() != WAIT_OBJECT) { ERROR("The mutex of the index manager can not be locked for opening"); return false; } res = UnsafeOpenImage(path_image_file, image_index); if(!mutex.Release()) { ERROR("The mutex of the index manager can not be unlocked"); return false; } return res; } bool IndexManager::UnsafeOpenImage(string& path_image_file, ImageIndex::Ptr *image_index) { if(path_image_file[0] == '/') path_image_file=path_image_file.substr(1, path_image_file.size()-1); path_image_file = file_manager_.root_dir() + path_image_file; // Look for the image in the list for (*image_index = index_list.begin(); *image_index != index_list.end(); (*image_index)++) { if ((*image_index)->path_name.compare(path_image_file) == 0) { (*image_index)->num_references++; return true; } } // Get image info ImageInfo image_info; if (!file_manager_.ReadImage(path_image_file, &image_info)) { ERROR("The image file '" << path_image_file << "' can not be read"); return false; } // IndexNode is created ImageIndex index_node; if(!index_node.Init(path_image_file, image_info)) { ERROR("The index for the image file '" << path_image_file << "' can not be created"); return false; } // Repeat the process with the image hyperlinks if(image_info.paths.size() > 0) { index_node.hyper_links.resize(image_info.paths.size()); map hyperlinks_visited; map hyperlinks_created; multimap::const_iterator it_find; pair::iterator,multimap::iterator> it_find_range; // Increase the number of references of the hyperlinks in the index list for (list::iterator i = index_list.begin() ; i != index_list.end(); i++) { it_find_range=image_info.paths.equal_range(i->path_name); for (it_find=it_find_range.first; it_find!=it_find_range.second; ++it_find) { i->num_references++; hyperlinks_visited.insert(*it_find); index_node.hyper_links[(*it_find).second]=i; } } // Add the rest of hyperlinks to the index list for (multimap::const_iterator i = image_info.paths.begin(); i != image_info.paths.end(); i++) { if (hyperlinks_visited.find(i->first) == hyperlinks_visited.end()) { if (hyperlinks_created.find(i->first) == hyperlinks_created.end()) { ImageIndex index_node_linked; if(!index_node_linked.Init(i->first, index_node.coding_parameters, image_info, i->second)) { ERROR("The index for the image file '" << i->first << "' can not be created"); return false; } index_list.push_back(index_node_linked); hyperlinks_created.insert(*i); } else index_list.back().num_references++; index_node.hyper_links[i->second]=--index_list.end(); } } } // The node is added to the list index_list.push_back(index_node); *image_index = --index_list.end(); return true; } bool IndexManager::CloseImage(const ImageIndex::Ptr& image_index) { bool res = false; if(mutex.Wait() != WAIT_OBJECT) { ERROR("The mutex of the index manager can not be locked for closing"); return false; } res = UnsafeCloseImage(image_index); if(!mutex.Release()) { ERROR("The mutex of the index manager can not be unlocked"); return false; } return res; } bool IndexManager::UnsafeCloseImage(const ImageIndex::Ptr& image_index) { TRACE("Closing the image '" << image_index->path_name << "'"); // Decrease the number of references image_index->num_references--; // If the number of references is zero, then the IndexNode is removed from the list if (image_index->num_references == 0) { for (vector::iterator>::iterator i = image_index->hyper_links.begin(); i != image_index->hyper_links.end(); i++) UnsafeCloseImage(*i); index_list.erase(image_index); } return true; } } esajpip-0.1~bzr33/src/jpeg2000/image_info.cc0000644000175000017500000000003112335423210020350 0ustar mathieumathieu#include "image_info.h" esajpip-0.1~bzr33/src/jpeg2000/codestream_index.cc0000644000175000017500000000003712335423210021576 0ustar mathieumathieu#include "codestream_index.h" esajpip-0.1~bzr33/src/jpeg2000/point.h0000644000175000017500000001143412335423210017257 0ustar mathieumathieu#ifndef _JPEG2000_POINT_H_ #define _JPEG2000_POINT_H_ #include namespace jpeg2000 { using namespace std; /** * Represents a couple of integer values that can * be used to identify a coordinate as well as a * size. This class can be printed and serialized. */ class Point { public: int x; ///< Value X int y; ///< Value Y /** * Initializes the object. */ Point() { x = y = 0; } /** * Initializes the object. * @param x Value X. * @param y Value Y. */ Point(int x, int y) { this->x = x; this->y = y; } /** * Copy constructor. */ Point(const Point& p) { *this = p; } /** * Copy assignment. */ Point& operator=(const Point& p) { x = p.x; y = p.y; return *this; } /** * Increments by one the two values. * @return The object itself. */ Point& operator++() { x++; y++; return *this; } /** * Decrements by one the two values. * @return The object itself. */ Point& operator--() { x--; y--; return *this; } /** * Increments the two values. * @param val Value to increment. * @return The object itself. */ Point& operator+=(int val) { x += val; y += val; return *this; } /** * Decrements the two values. * @param val Value to decrement. * @return The object itself. */ Point& operator-=(int val) { x -= val; y -= val; return *this; } /** * Multiplies the two values by one value. * @param val Value to multiply. * @return The object itself. */ Point& operator*=(int val) { x *= val; y *= val; return *this; } /** * Divides the two values by one value. * @param val Value to divide. * @return The object itself. */ Point& operator/=(int val) { x /= val; y /= val; return *this; } /** * Returns the sum of a point with an integer value. * The value is added to the two values of the point. */ friend Point operator+(const Point& a, int value) { return Point(a.x + value, a.y + value); } /** * Returns the subtraction of a point with an integer value. * The value is subtracted from the two values of the point. */ friend Point operator-(const Point& a, int value) { return Point(a.x - value, a.y - value); } /** * Returns the multiplication of a point with an integer value. * The value is multiplied to the two values of the point. */ friend Point operator*(const Point& a, int value) { return Point(a.x * value, a.y * value); } /** * Returns the division of a point with an integer value. * The value is divided to the two values of the point. */ friend Point operator/(const Point& a, int value) { return Point(a.x / value, a.y / value); } /** * Returns the sum of two points. The operation is * applied each value of each point. */ friend Point operator+(const Point& a, const Point& b) { return Point(a.x + b.x, a.y + b.y); } /** * Returns the subtraction of two points. The operation is * applied each value of each point. */ friend Point operator-(const Point& a, const Point& b) { return Point(a.x - b.x, a.y - b.y); } /** * Returns the multiplication of two points. The operation is * applied each value of each point. */ friend Point operator*(const Point& a, const Point& b) { return Point(a.x * b.x, a.y * b.y); } /** * Returns the division of two points. The operation is * applied each value of each point. */ friend Point operator/(const Point& a, const Point& b) { return Point(a.x / b.x, a.y / b.y); } /** * Returns true if the two points are equal. */ friend bool operator==(const Point& a, const Point& b) { return ((a.x == b.x) && (a.y == b.y)); } /** * Returns true if the two points are not equal. */ friend bool operator!=(const Point& a, const Point& b) { return ((a.x != b.x) || (a.y != b.y)); } friend ostream& operator << (ostream &out, const Point &point) { out << "(" << point.x << ", " << point.y << ")"; return out; } template T& SerializeWith(T& stream) { return (stream & x & y); } virtual ~Point() { } }; /** * It is a synonymous of the class Point. * * @see Point */ typedef Point Size; } #endif /* _JPEG2000_POINT_H_ */ esajpip-0.1~bzr33/src/jpeg2000/image_index.cc0000644000175000017500000001701612335423210020537 0ustar mathieumathieu#include "trace.h" #include "image_index.h" namespace jpeg2000 { bool ImageIndex::Init(const string& path_name, const ImageInfo& image_info) { num_references = 1; this->path_name = path_name; this->coding_parameters = CodingParameters::Ptr(new CodingParameters(image_info.coding_parameters)); meta_data = image_info.meta_data; if (image_info.paths.size() == 0) { base::copy(codestreams, image_info.codestreams); max_resolution.resize(codestreams.size(), -1); for (vector::const_iterator i = codestreams.begin(); i != codestreams.end(); i++) { last_plt.push_back(0); last_packet.push_back(0); last_offset_PLT.push_back(0); last_offset_packet.push_back(0); packet_indexes.push_back(PacketIndex()); } } rdwr_lock = RdWrLock::Ptr(new RdWrLock()); return rdwr_lock->Init(); } bool ImageIndex::Init(const string& path_name, CodingParameters::Ptr coding_parameters, const ImageInfo& image_info, int index) { num_references = 1; this->path_name = path_name; this->coding_parameters = coding_parameters; meta_data=image_info.meta_data_hyperlinks[index]; codestreams.push_back(image_info.codestreams[index]); max_resolution.push_back(-1); last_plt.push_back(0); last_packet.push_back(0); last_offset_PLT.push_back(0); last_offset_packet.push_back(0); packet_indexes.push_back(PacketIndex()); rdwr_lock = RdWrLock::Ptr(new RdWrLock()); return rdwr_lock->Init(); } bool ImageIndex::BuildIndex(int ind_codestream, int r) { File file; bool res = true; if(!(res = res && rdwr_lock->Release())) ERROR("The lock of the image '" << path_name << "' can not be released"); if(!(res = res && (rdwr_lock->WaitForWriting() == WAIT_OBJECT))) ERROR("The lock of the image '" << path_name << "' can not be taken for writing"); // Open file for reading if((res = res && file.OpenForReading(path_name))) { // Check if PacketIndex has been created if (packet_indexes[ind_codestream].Size() == 0) packet_indexes[ind_codestream] = PacketIndex(file.GetSize()); // Check the upper top of the index (to build) int max_index; if ((r < coding_parameters->num_levels) && (coding_parameters->IsResolutionProgression())) { // The max_index is the last packet index of the resolution r Packet packet(0, r + 1, 0, Size(0, 0)); max_index = coding_parameters->GetProgressionIndex(packet) - 1; } else { // The max_index is the last packet of the image file Size precinct_point = coding_parameters->GetPrecincts(coding_parameters->num_levels, coding_parameters->size) - 1; Packet packet(coding_parameters->num_layers - 1, coding_parameters->num_levels, coding_parameters->num_components - 1, precinct_point); max_index = coding_parameters->GetProgressionIndex(packet); } uint64_t length_packet = 0; while (packet_indexes[ind_codestream].Size() <= max_index) { //GetPLTLength(file, ind_codestream, &length_packet); res = res && GetPLTLength(file, ind_codestream, &length_packet); GetOffsetPacket(file, ind_codestream, length_packet); } file.Close(); } if(!(res = res && rdwr_lock->Release())) ERROR("The lock of the image '" << path_name << "' can not be released"); if(!(res = res && (rdwr_lock->Wait() == WAIT_OBJECT))) ERROR("The lock of the image '" << path_name << "' can not be taken for reading"); return res; } bool ImageIndex::GetPLTLength(const File& file, int ind_codestream, uint64_t *length_packet) { bool res = true; vector& plt = codestreams[ind_codestream].PLT_markers; // Get packet plt offset if (last_offset_PLT[ind_codestream] == 0) res = res && file.Seek(plt[last_plt[ind_codestream]].offset, SEEK_SET); else res = res && file.Seek(last_offset_PLT[ind_codestream], SEEK_SET); // Get packet length uint8_t buf_packet = 0; uint8_t length_packet_partial; uint8_t partial = 1; *length_packet = 0; while (partial) { res = res && file.Read(&buf_packet, 1); partial = buf_packet & 128; // To get if the packet is final or not length_packet_partial = buf_packet & 127; // To get the packet length *length_packet = (*length_packet << 7) | length_packet_partial; } last_offset_PLT[ind_codestream] = file.GetOffset(); if (last_offset_PLT[ind_codestream] == (plt[last_plt[ind_codestream]].offset + plt[last_plt[ind_codestream]].length)) { last_plt[ind_codestream]++; last_offset_PLT[ind_codestream] = 0; } return res; } void ImageIndex::GetOffsetPacket(const File& file, int ind_codestream, uint64_t length_packet) { uint64_t offset; vector& packets = codestreams[ind_codestream].packets; if (last_offset_packet[ind_codestream] == 0) offset = packets[last_packet[ind_codestream]].offset; else offset = last_offset_packet[ind_codestream]; packet_indexes[ind_codestream].Add(FileSegment(offset, length_packet)); last_offset_packet[ind_codestream] = offset + length_packet; if (last_offset_packet[ind_codestream] == (packets[last_packet[ind_codestream]].offset + packets[last_packet[ind_codestream]].length)) { last_packet[ind_codestream]++; last_offset_packet[ind_codestream] = 0; } } FileSegment ImageIndex::GetPacket(int num_codestream, const Packet& packet, int *offset) { FileSegment segment = FileSegment::Null; if (hyper_links.size()>0) { if(packet.resolution > hyper_links[num_codestream]->max_resolution.back()) { if(!hyper_links[num_codestream]->BuildIndex(0,packet.resolution)) ERROR("The packet index could not be created"); hyper_links[num_codestream]->max_resolution.back() = packet.resolution; } } else { if(packet.resolution > max_resolution[num_codestream]) { if(!BuildIndex(num_codestream, packet.resolution)) ERROR("The packet index could not be created"); max_resolution[num_codestream] = packet.resolution; } } PacketIndex& packet_index = (hyper_links.size()>0) ? hyper_links[num_codestream]->packet_indexes[0]: packet_indexes[num_codestream]; //PacketIndex& packet_index = packet_indexes[num_codestream]; int idx = coding_parameters->GetProgressionIndex(packet); segment = packet_index[idx]; if(offset != NULL) { *offset = 0; if(coding_parameters->progression == CodingParameters::RPCL_PROGRESSION) { for(int l = packet.layer; l > 0; l--) *offset += packet_index[--idx].length; } else { Packet p_aux = packet; for(int l = 0; l < packet.layer; l++) { p_aux.layer = l; idx = coding_parameters->GetProgressionIndex(p_aux); *offset += packet_index[idx].length; } } } return segment; } bool ImageIndex::ReadLock(const Range& range) { bool res = true; if (hyper_links.size() <= 0) res = (rdwr_lock->Wait() == WAIT_OBJECT); else { for(int i = range.first; i <= range.last; i++) res = res && hyper_links[i]->ReadLock(); } return res; } bool ImageIndex::ReadUnlock(const Range& range) { bool res = true; if (hyper_links.size() <= 0) res = rdwr_lock->Release(); else { for(int i = range.first; i <= range.last; i++) res = res && hyper_links[i]->ReadUnlock(); } return res; } } esajpip-0.1~bzr33/src/jpeg2000/image_info.h0000644000175000017500000000543712335423210020231 0ustar mathieumathieu#ifndef _JPEG2000_IMAGE_INFO_H_ #define _JPEG2000_IMAGE_INFO_H_ #include #include "base.h" #include "data/file.h" #include "codestream_index.h" #include "coding_parameters.h" #include "meta_data.h" namespace jpeg2000 { /** * Contains the indexing information of a JPEG2000 image. * This class can be serialized and printed. * * @see CodingParameters * @see CodestreamIndex * @see Metadata */ class ImageInfo { public: Metadata meta_data; ///< Meta-data information multimap paths; ///< Paths of the hyperlinks (if any) CodingParameters coding_parameters; ///< Coding parameters vector codestreams; ///< Codestreams information vector meta_data_hyperlinks; ///< Meta-data of the hyperlinks /** * Empty constructor. */ ImageInfo() { } /** * Copy constructor. */ ImageInfo(const ImageInfo& info) { *this = info; } /** * Copy assignment. */ const ImageInfo& operator=(const ImageInfo& info) { base::copy(paths, info.paths); coding_parameters = info.coding_parameters; base::copy(codestreams, info.codestreams); meta_data=info.meta_data; base::copy(meta_data_hyperlinks, info.meta_data_hyperlinks); return *this; } template T& SerializeWith(T& stream) { return (stream & paths & coding_parameters & codestreams & meta_data & meta_data_hyperlinks); } friend ostream& operator <<(ostream &out, const ImageInfo &info) { out << "Coding parameters: " << endl << "---------------------- " << endl << info.coding_parameters << endl << endl; if (info.paths.size() > 0) { for (multimap::const_iterator i = info.paths.begin(); i != info.paths.end(); i++) { out << "Codestream index " << (*i).second + 1 << ":" << endl; out << "------------------------" << endl; out << "Path: " << (*i).first << endl; out << info.codestreams[(*i).second] << endl << endl; } } else { int ind = 0; for (vector::const_iterator i = info.codestreams.begin(); i != info.codestreams.end(); i++, ind++) { out << "Codestream index " << ind << ":" << endl; out << "------------------------" << endl << *i << endl << endl; } } out << endl << "Meta-data: "; out << info.meta_data << endl << endl; out << endl << "Meta-data-hyperlinks: "; for(vector::const_iterator i = info.meta_data_hyperlinks.begin(); i != info.meta_data_hyperlinks.end(); i++) out << *i << " "; return out; } virtual ~ImageInfo() { } }; } #endif /* _JPEG2000_IMAGE_INFO_H_ */ esajpip-0.1~bzr33/src/jpeg2000/packet.cc0000644000175000017500000000002512335423210017525 0ustar mathieumathieu#include "packet.h" esajpip-0.1~bzr33/src/jpeg2000/point.cc0000644000175000017500000000002312335423210017405 0ustar mathieumathieu#include "point.h" esajpip-0.1~bzr33/src/jpeg2000/place_holder.h0000644000175000017500000000436412335423210020553 0ustar mathieumathieu#ifndef _JPEG2000_PLACE_HOLDER_H_ #define _JPEG2000_PLACE_HOLDER_H_ #include "data/file_segment.h" namespace jpeg2000 { using namespace data; /** * Contains the information of a place-holder. This class * can be printed and serialized. */ class PlaceHolder { public: int id; ///< Place-holder identifier. bool is_jp2c; ///< true if refers to a codestream. FileSegment header; ///< File segment associated to the box header uint64_t data_length; ///< Length of the place-holder data /** * Initializes the object. */ PlaceHolder() { id = 0; is_jp2c = false; data_length = 0; } /** * Initializes the object. * @param id Place-holder identifier. * @param is_jp2c Indicates if is a codestream place-holder. * @param header File segment of the associated header. * @param data_length Length of the place-holder data. */ PlaceHolder(int id, bool is_jp2c, const FileSegment &header, uint64_t data_length) { this->id = id; this->is_jp2c = is_jp2c; this->header = header; this->data_length = data_length; } /** * Copy constructor. */ PlaceHolder(const PlaceHolder& place_holder) { *this = place_holder; } template T& SerializeWith(T& stream) { return (stream & id & is_jp2c & header & data_length); } /** * Copy assignment. */ PlaceHolder& operator=(const PlaceHolder& place_holder) { id = place_holder.id; is_jp2c = place_holder.is_jp2c; header = place_holder.header; data_length = place_holder.data_length; return *this; } friend ostream& operator << (ostream &out, const PlaceHolder &place_holder) { out << "Id: " << place_holder.id << endl; out << "JP2C: " << (place_holder.is_jp2c ? "Yes" : "No") << endl; out << "Header: " << place_holder.header << endl; out << "Data length: " << place_holder.data_length << endl; return out; } /** * Returns the length of the place-holder. */ int length() const { return (44 + header.length); } virtual ~PlaceHolder() { } }; } #endif /* _JPEG2000_PLACE_HOLDER_H_ */ esajpip-0.1~bzr33/src/jpeg2000/range.cc0000644000175000017500000000002412335423210017351 0ustar mathieumathieu#include "range.h" esajpip-0.1~bzr33/src/jpeg2000/packet_index.h0000644000175000017500000000615212335423210020565 0ustar mathieumathieu#ifndef _JPEG2000_PACKET_INDEX_H_ #define _JPEG2000_PACKET_INDEX_H_ #include "data/vint_vector.h" #include "data/file_segment.h" namespace jpeg2000 { using namespace data; /** * Class used for indexing the packets of a codestream image. * The class vint_vector is used internally to * store the offsets of the packets with the minimum required * bytes. * * @see data::vint_vector */ class PacketIndex { private: /** * Vector of packet offsets. */ vint_vector offsets; /** * Vector of file segments to handle the different * sets of packets that are not contiguous. */ vector aux; public: enum { /** * All the offsets must be greater than this value. */ MINIMUM_OFFSET = 64 }; /** * Empty constructor. */ PacketIndex() { } /** * Initializes the object. * @param max_offset Maximum value for an offset. */ PacketIndex(uint64_t max_offset) { assert(max_offset > 0); int num_bytes = 0; while(max_offset > 0) { max_offset >>= 8; num_bytes++; } offsets.set_num_bytes(num_bytes); } /** * Copy constructor. */ PacketIndex(const PacketIndex& index) { *this = index; } /** * Copy assignment. */ const PacketIndex& operator=(const PacketIndex& index) { offsets = index.offsets; aux.clear(); for(vector::const_iterator i = index.aux.begin(); i != index.aux.end(); i++) aux.push_back(*i); return *this; } /** * Adds a new packet segment to the index. * @param segment Fiel segment associated to the packet. * @return The object itself. */ PacketIndex& Add(const FileSegment& segment) { assert(segment.offset >= MINIMUM_OFFSET); int last = aux.size() - 1; if(last < 0) { aux.push_back(segment); offsets.push_back(0); } else { if(aux[last].IsContiguousTo(segment)) { offsets.back() = aux[last].offset; offsets.push_back(last); aux[last] = segment; } else { assert(last < (MINIMUM_OFFSET - 1)); offsets.push_back(last + 1); aux.push_back(segment); } } return *this; } /** * Returns the number of elements of the vector. */ int Size() const { return offsets.size(); } /** * Clears the content. */ void Clear() { offsets.clear(); aux.clear(); } /** * Operator used for accessing the items. * @param i Item index. * @return File segment of the packet. */ FileSegment operator[](int i) const { uint64_t off_i = offsets[i]; if(off_i < MINIMUM_OFFSET) return aux[off_i]; else { uint64_t off_i1 = offsets[i + 1]; if(off_i1 < MINIMUM_OFFSET) off_i1 = aux[off_i1].offset; return FileSegment(off_i, off_i1 - off_i); } } virtual ~PacketIndex() { } }; } #endif /* _JPEG2000_PACKET_INDEX_H_ */ esajpip-0.1~bzr33/src/jpeg2000/meta_data.cc0000644000175000017500000000003012335423210020171 0ustar mathieumathieu#include "meta_data.h" esajpip-0.1~bzr33/src/jpeg2000/file_manager.cc0000644000175000017500000004207312335423210020700 0ustar mathieumathieu#include "file_manager.h" #include "trace.h" namespace jpeg2000 { using namespace std; using namespace data; #define EOC_MARKER 0xFFD9 #define SOC_MARKER 0xFF4F #define SIZ_MARKER 0xFF51 #define COD_MARKER 0xFF52 #define SOT_MARKER 0xFF90 #define PLT_MARKER 0xFF58 #define SOD_MARKER 0xFF93 #define JP2C_BOX_ID 0x6A703263 #define XML__BOX_ID 0x786D6C20 #define ASOC_BOX_ID 0x61736F63 #define NLST_BOX_ID 0x6E6C7374 #define JPCH_BOX_ID 0x6A706368 #define FTBL_BOX_ID 0x6674626C #define DBTL_BOX_ID 0x6474626C #define URL__BOX_ID 0x75726C20 #define FLST_BOX_ID 0x666C7374 string FileManager::GetCacheFileName(const string& path_image_file) { string name_cache_file; size_t begin_pos = 0; while (!isalpha(path_image_file[begin_pos])) begin_pos++; name_cache_file=path_image_file.substr(begin_pos,path_image_file.size()-begin_pos); // Replace "." with "_" for (size_t j; (j = name_cache_file.find(".")) != string::npos;) name_cache_file.replace(j, 1, "_"); // Replace "/" with "_" for (size_t j; (j = name_cache_file.find("/")) != string::npos;) name_cache_file.replace(j, 1, "_"); // Add the file extension ".cache" //name_cache_file+=".cache"; return name_cache_file; } bool FileManager::ExistCacheImage(const string& path_image_file, string *path_cache_file) { // Get the path cache file *path_cache_file = cache_dir_ + GetCacheFileName(path_image_file) + ".cache"; struct stat cache_att; // Cache file exists if (stat(path_cache_file->c_str(), &cache_att) == 0) { // Get last modification dates of image and cache files struct stat file_att; stat(path_image_file.c_str(), &file_att); // Check if last modification date of image file is lower than // last modification date of cache file if (file_att.st_mtime < cache_att.st_mtime) return true; } return false; } bool FileManager::ReadImage(const string& name_image_file, ImageInfo *image_info) { bool res = true; string path_cache_file; // Cache file does not exist or it is not updated if (!ExistCacheImage(name_image_file, &path_cache_file)) { File f; // Get file extension string extension = ""; size_t pos = name_image_file.find_last_of("."); if (pos != string::npos) extension = name_image_file.substr(pos); // J2C image if (extension.compare(".j2c") == 0) { image_info->codestreams.push_back(CodestreamIndex()); CodingParameters *cp = &image_info->coding_parameters; CodestreamIndex *ci = &image_info->codestreams.back(); if (!f.OpenForReading(name_image_file.c_str())) { ERROR("Impossible to open file: '" << name_image_file << "'..."); return false; } res = res && ReadCodestream(f, cp, ci); f.Close(); } // JP2 image else if (extension.compare(".jp2") == 0) { image_info->codestreams.push_back(CodestreamIndex()); if (!f.OpenForReading(name_image_file.c_str())) { ERROR("Impossible to open file: '" << name_image_file << "'..."); return false; } res = res && ReadJP2(f, image_info); f.Close(); } // JPX image else if (extension.compare(".jpx") == 0) { if (!f.OpenForReading(name_image_file.c_str())) { ERROR("Impossible to open file: '" << name_image_file << "'..."); return false; } res = res && ReadJPX(f, image_info); f.Close(); } else { ERROR("File type not supported..."); return false; } // Serialize the info of the image in a cache file struct stat cache_dir_stat; if (stat(cache_dir_.c_str(), &cache_dir_stat)==0) res = res && OutputStream().Open(path_cache_file.c_str()).Serialize(*image_info); } // Cache file is updated else { // Get info of the image res = res && InputStream().Open(path_cache_file.c_str()).Serialize(*image_info); } return res; } bool FileManager::ReadCodestream(const File& file, CodingParameters *params, CodestreamIndex *index) { bool res = true; // Get markers bool plts = false; uint16_t value = 0; while (res = res && file.ReadReverse(&value), res && (value != EOC_MARKER)) { switch (value) { case SOC_MARKER: TRACE("SOC marker..."); index->header.offset = file.GetOffset() - 2; break; case SIZ_MARKER: TRACE("SIZ marker..."); res = res && ReadSIZMarker(file, params); break; case COD_MARKER: TRACE("COD marker..."); res = res && ReadCODMarker(file, params); break; case SOT_MARKER: TRACE("SOT marker..."); res = res && ReadSOTMarker(file, index); break; case PLT_MARKER: TRACE("PLT marker..."); res = res && ReadPLTMarker(file, index); if (res) plts = true; break; case SOD_MARKER: TRACE("SOD marker..."); res = res && ReadSODMarker(file, index); break; default: res = res && file.ReadReverse(&value) && file.Seek(value - 2, SEEK_CUR); } } // Check if the image has been read in a right way if (value == EOC_MARKER) { // Check if the image has PLT marker if (plts) return true; else { ERROR("The code-stream does not include any PLT marker"); return false; } } else { ERROR("The code-stream does not end with an EOC marker"); return false; } } bool FileManager::ReadSIZMarker(const File& file, CodingParameters *params) { bool res = true; // To jump Lsiz, CA res = res && file.Seek(4, SEEK_CUR); // Get image height and width uint32_t FE[4]; for (int i = 0; i < 4; i++) res = res && file.ReadReverse(&FE[i]); // height=F1-E1 // width=F2-E2 params->size = Size(FE[0] - FE[2], FE[1] - FE[3]); // Get T2, T1, omegaT2, omegaT1 uint32_t tiling[4]; for (int i = 0; i < 4; i++) res = res && file.ReadReverse(&tiling[i]); // Get number of components uint16_t num_components = 0; res = res && file.ReadReverse(&num_components); params->num_components = num_components; // To jump to the end of the marker res = res && file.Seek(3 * num_components, SEEK_CUR); return res; } bool FileManager::ReadCODMarker(const File& file, CodingParameters *params) { bool res = true; // Get CS0 parameter uint8_t cs_buf = 0; res = res && file.Seek(2, SEEK_CUR) && file.ReadReverse(&cs_buf); // Get progression order uint8_t progression = 0; res = res && file.ReadReverse(&progression); params->progression = progression; // Get number of quality layers uint16_t quality_layers = 0; // To jump MC res = res && file.ReadReverse(&quality_layers) && file.Seek(1, SEEK_CUR); params->num_layers = quality_layers; // Get transform levels uint8_t transform_levels = 0; // To jump 4 bytes (ECB2,ECB1,MS,WT) res = res && file.ReadReverse(&transform_levels) && file.Seek(4, SEEK_CUR); params->num_levels = transform_levels; // Get precint sizes for each resolution int height, width; uint8_t size_precinct; params->precinct_size.clear(); for (int i = 0; i <= params->num_levels; i++) { if (cs_buf & 1) { res = res && file.ReadReverse(&size_precinct); height = 1L << ((size_precinct & 0xF0) >> 4); width = 1L << (size_precinct & 0x0F); params->precinct_size.push_back(Size(width, height)); } else { height = ceil((double) params->size.y / (1L << i)); width = ceil((double) params->size.x / (1L << i)); params->precinct_size.insert(params->precinct_size.begin(), Size(width, height)); } } return res; } bool FileManager::ReadSOTMarker(const File& file, CodestreamIndex *index) { bool res = true; // Get offset of the codestream header if (index->header.length == 0) index->header.length = file.GetOffset() - 2 - index->header.offset; // Get Ltp uint32_t ltp = 0; // To jump Lsot, it, itp, ntp res = res && file.Seek(4, SEEK_CUR) && file.ReadReverse(<p) && file.Seek(2, SEEK_CUR); index->packets.push_back(FileSegment(file.GetOffset(), ltp - 12)); return res; } bool FileManager::ReadPLTMarker(const File& file, CodestreamIndex *index) { bool res = true; // Get PLT offset uint64_t PLT_offset = file.GetOffset() + 3; // Get Lplt uint16_t lplt = 0; res = res && file.ReadReverse(&lplt); res = res && file.Seek(lplt - 2, SEEK_CUR); // PLT marker length = Lplt - 3 (2 bytes Lplt and 1 byte iplt) index->PLT_markers.push_back(FileSegment(PLT_offset, lplt - 3)); return res; } bool FileManager::ReadSODMarker(const File& file, CodestreamIndex *index) { bool res = true; // Get packets info FileSegment& fs = index->packets.back(); fs.length = fs.length - (file.GetOffset() - fs.offset); fs.offset = file.GetOffset(); res = res && file.Seek(fs.length, SEEK_CUR); return res; } bool FileManager::ReadBoxHeader(const File &file, uint32_t *type_box, uint64_t *length_box) { bool res = true; // Get L, if it is not 0 or 1, then box length is L uint32_t L = 0; res = res && file.ReadReverse(&L); *length_box = L - 8; // Get T (box type) uint32_t T = 0; res = res && file.ReadReverse(&T); *type_box = T; // XL indicates the box length if (L == 1) { uint64_t XL = 0; res = res && file.ReadReverse(&XL); *length_box = XL - 16; } // Box length = eof_offset - offset else if (L == 0) { *length_box = file.GetSize() - file.GetOffset(); } return res; } bool FileManager::ReadJP2(const File& file, ImageInfo *image_info) { bool res = true; // Get boxes uint32_t type_box; uint64_t length_box; int pini=0, plen=0, pini_box=0, plen_box=0; //int metadata_bin=1; while (file.GetOffset() != file.GetSize() && res) { pini_box=file.GetOffset(); plen = pini_box-pini; res = res && ReadBoxHeader(file, &type_box, &length_box); plen_box=file.GetOffset()-pini_box; switch (type_box) { case JP2C_BOX_ID: TRACE("JP2C box..."); image_info->meta_data.meta_data.push_back(FileSegment(pini,plen)); res = res && ReadCodestream(file, &image_info->coding_parameters, &image_info->codestreams.back()); image_info->meta_data.place_holders.push_back(PlaceHolder(image_info->codestreams.size()-1, true, FileSegment(pini_box, plen_box), length_box)); pini=file.GetOffset(); plen=0; break; /*case XML__BOX_ID: TRACE("XML box..."); image_info->meta_data.meta_data.push_back(FileSegment(pini,plen)); // Get meta_data info res = res && file.Seek(length_box, SEEK_CUR); image_info->meta_data.place_holders.push_back(PlaceHolder(metadata_bin, false, FileSegment(pini_box, plen_box), length_box)); metadata_bin++; pini=file.GetOffset(); plen=0; break;*/ default: res = res && file.Seek(length_box, SEEK_CUR); } } image_info->meta_data.meta_data.push_back(FileSegment(pini,file.GetOffset()-pini)); return res; } bool FileManager::ReadJPX(const File& file, ImageInfo *image_info) { bool res = true; // Get boxes uint32_t type_box; uint64_t length_box; string path_file; uint16_t data_reference; vector v_data_reference; vector v_path_file; int pini=0, plen=0, pini_box=0, plen_box=0, pini_ftbl, plen_ftbl; //int metadata_bin=1; int num_flst; while (file.GetOffset() != file.GetSize() && res) { pini_box=file.GetOffset(); plen = pini_box-pini; res = res && ReadBoxHeader(file, &type_box, &length_box); plen_box=file.GetOffset()-pini_box; switch (type_box) { case JPCH_BOX_ID: TRACE("JPCH box..."); image_info->codestreams.push_back(CodestreamIndex()); break; case JP2C_BOX_ID: TRACE("JP2C box..."); image_info->meta_data.meta_data.push_back(FileSegment(pini,plen)); res = res && ReadCodestream(file, &image_info->coding_parameters, &image_info->codestreams.back()); image_info->meta_data.place_holders.push_back(PlaceHolder(image_info->codestreams.size()-1, true, FileSegment(pini_box, plen_box), length_box)); pini=file.GetOffset(); plen=0; break; /*case ASOC_BOX_ID: TRACE("ASOC box..."); image_info->meta_data.meta_data.push_back(FileSegment(pini,plen)); res = res && file.Seek(length_box, SEEK_CUR); image_info->meta_data.place_holders.push_back(PlaceHolder(metadata_bin, false, FileSegment(pini_box, plen_box), length_box)); metadata_bin++; pini=file.GetOffset(); plen=0; break; case XML__BOX_ID: TRACE("XML box..."); image_info->meta_data.meta_data.push_back(FileSegment(pini,plen)); res = res && file.Seek(length_box, SEEK_CUR); image_info->meta_data.place_holders.push_back(PlaceHolder(metadata_bin, false, FileSegment(pini_box, plen_box), length_box)); metadata_bin++; pini=file.GetOffset(); plen=0; break;*/ case FTBL_BOX_ID: TRACE("FTBL box..."); image_info->meta_data.meta_data.push_back(FileSegment(pini,plen)); num_flst=0; pini_ftbl=pini_box; plen_ftbl=plen_box; break; case FLST_BOX_ID: TRACE("FLST box..."); res = res && ReadFlstBox(file, length_box, &data_reference); if (num_flst) image_info->meta_data.meta_data.push_back(FileSegment(0,0)); num_flst++; image_info->meta_data.place_holders.push_back(PlaceHolder(v_data_reference.size(), true, FileSegment(pini_ftbl,plen_ftbl), 0)); v_data_reference.push_back(data_reference); pini=file.GetOffset(); plen=0; break; case DBTL_BOX_ID: TRACE("DBTL box..."); res = res && file.Seek(2, SEEK_CUR); break; case URL__BOX_ID: TRACE("URL box..."); // Add the paths of the hyperlinked images to the paths vector res = res && ReadUrlBox(file, length_box, &path_file); //path_file=root_dir_+path_file; /// OJOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO v_path_file.push_back(path_file); break; default: res = res && file.Seek(length_box, SEEK_CUR); } } image_info->meta_data.meta_data.push_back(FileSegment(pini,file.GetOffset()-pini)); int ind_codestream=0; for (vector::const_iterator i = v_data_reference.begin(); i!=v_data_reference.end(); i++) { image_info->paths.insert(pair (v_path_file[*i-1],ind_codestream)); ind_codestream++; } if (image_info->paths.size()>0) { image_info->codestreams.resize(image_info->paths.size()); image_info->meta_data_hyperlinks.resize(image_info->paths.size()); } // Get image info of the hyperlinked images for (multimap::iterator i = image_info->paths.begin(); i != image_info->paths.end() && res; i++) { ImageInfo image_info_hyperlink; res = res && ReadImage((*i).first, &image_info_hyperlink); image_info->coding_parameters = image_info_hyperlink.coding_parameters; image_info->codestreams[(*i).second] = image_info_hyperlink.codestreams.back(); image_info->meta_data_hyperlinks[(*i).second] = image_info_hyperlink.meta_data; } return res; } bool FileManager::ReadNlstBox(const File& file, int *num_codestream, int length_box) { bool res = true; // Get the codestream number uint32_t an; while (res && (length_box > 0)) { res = res && file.ReadReverse(&an); if ((an >> 24) == 1) { *num_codestream = an & 0x00FFFFFF; } length_box -= 4; } return res; } bool FileManager::ReadFlstBox(const File& file, uint64_t length_box, uint16_t *data_reference) { bool res = true; // Get the path of the hyperlinked image res = res && file.Seek(14, SEEK_CUR); res = res && file.ReadReverse(data_reference); return res; } bool FileManager::ReadUrlBox(const File& file, uint64_t length_box, string *path_file) { bool res = true; // Get the path of the hyperlinked image res = res && file.Seek(4, SEEK_CUR); char path_char[length_box - 4]; res = res && file.Read(path_char, length_box - 4); *path_file = path_char; size_t found = path_file->find("file://") + 7; *path_file = path_file->substr(found); //*path_file = path_file->substr(found + 2); // Replace "./" with the root_dir_ size_t pos = path_file->find("./"); if (pos != string::npos) *path_file = path_file->substr(0, pos) + root_dir_ + path_file->substr(pos + 2); return res; } } esajpip-0.1~bzr33/src/jpeg2000/meta_data.h0000644000175000017500000000305412335423210020044 0ustar mathieumathieu#ifndef _JPEG2000_META_DATA_H_ #define _JPEG2000_META_DATA_H_ #include #include "base.h" #include "jpeg2000/place_holder.h" namespace jpeg2000 { using namespace data; /** * Contains the indexing information associated to the * meta-data of a JPEG2000 image file. This class can * be printed and serialized. */ class Metadata { public: /** * File segments of all the meta-data blocks. */ vector meta_data; /** * Associated place-holders. */ vector place_holders; /** * Empty constructor. */ Metadata() { } /** * Copy constructor. */ Metadata(const Metadata& info) { *this = info; } template T& SerializeWith(T& stream) { return (stream & meta_data & place_holders); } /** * Copy assignment. */ Metadata& operator=(const Metadata& info) { base::copy(meta_data, info.meta_data); base::copy(place_holders, info.place_holders); return *this; } friend ostream& operator << (ostream &out, const Metadata &info) { out << endl << "Meta-data: "; for(vector::const_iterator i = info.meta_data.begin(); i != info.meta_data.end(); i++) out << *i << " "; out << endl << "Place Holders: "; for(vector::const_iterator i = info.place_holders.begin(); i != info.place_holders.end(); i++) out << *i << " "; return out; } virtual ~Metadata() { } }; } #endif /* _JPEG2000_META_DATA_H_ */ esajpip-0.1~bzr33/src/jpeg2000/coding_parameters.h0000644000175000017500000001777212335423210021627 0ustar mathieumathieu#ifndef _JPEG2000_CODING_PARAMETERS_H_ #define _JPEG2000_CODING_PARAMETERS_H_ #include #include #include "tr1_compat.h" #include "base.h" #include "point.h" #include "trace.h" #include "packet.h" namespace jpeg2000 { /** * Contains the coding parameters of a JPEG2000 image codestream. * This class can be serialized and printed. */ class CodingParameters { private: /** * Contains the number of precincts of each * resolution level. */ vector total_precincts; /** * Fills the vector total_precincts. */ void FillTotalPrecinctsVector(); /** * Returns the index of a packet according to the RPCL progression. * @param l Quality layer. * @param r Resolution level. * @param c Component. * @param px Precinct position X. * @param py Precinct position Y. */ int GetProgressionIndexRPCL(int l, int r, int c, int px, int py) { Size precinct_point = GetPrecincts(r, size); return (total_precincts[r] * num_components * num_layers) + (py * precinct_point.x * num_components * num_layers) + (px * num_components * num_layers) + (c * num_layers) + l; } /** * Returns the index of a packet according to the RLCP progression. * @param l Quality layer. * @param r Resolution level. * @param c Component. * @param px Precinct position X. * @param py Precinct position Y. */ int GetProgressionIndexRLCP(int l, int r, int c, int px, int py) { Size precinct_point = GetPrecincts(r, size); return (total_precincts[r] * num_components * num_layers) + (l * num_components * precinct_point.x * precinct_point.y) + (c * precinct_point.x * precinct_point.y) + (py * precinct_point.x) + px; } /** * Returns the index of a packet according to the LRCP progression. * @param l Quality layer. * @param r Resolution level. * @param c Component. * @param px Precinct position X. * @param py Precinct position Y. */ int GetProgressionIndexLRCP(int l, int r, int c, int px, int py) { Size precinct_point = GetPrecincts(r, size); return (l * total_precincts[num_levels + 1] * num_components) + (num_components * total_precincts[r]) + (c * precinct_point.x * precinct_point.y) + (py * precinct_point.x) + px; } public: Size size; ///< Image size int num_levels; ///< Number of resolution levels int num_layers; ///< Number of quality layers int progression; ///< Progression order int num_components; ///< Number of components /** * Precinct sizes of each resolution level. */ vector precinct_size; /** * Pointer to an object of this class. */ typedef SHARED_PTR Ptr; /** * All the progression orders defined in the JPEG2000 * standard (Part 1). */ enum { LRCP_PROGRESSION = 0, ///< LRCP RLCP_PROGRESSION = 1, ///< RLCP RPCL_PROGRESSION = 2, ///< RPCL PCRL_PROGRESSION = 3, ///< PCRL CPRL_PROGRESSION = 4 ///< CPRL }; /** * Initializes the object. */ CodingParameters() { num_levels = 0; num_layers = 0; progression = 0; num_components = 0; } /** * Copy constructor. */ CodingParameters(const CodingParameters& cod_params) { *this = cod_params; } /** * Copy assignment. */ const CodingParameters& operator=(const CodingParameters& cod_params) { size = cod_params.size; num_levels = cod_params.num_levels; num_layers = cod_params.num_layers; progression = cod_params.progression; num_components = cod_params.num_components; base::copy(precinct_size, cod_params.precinct_size); base::copy(total_precincts, cod_params.total_precincts); return *this; } template T& SerializeWith(T& stream) { return (stream & size & num_levels & num_layers & progression & num_components & precinct_size); } friend ostream& operator <<(ostream &out, const CodingParameters ¶ms) { out << "Progression: " << (params.progression == LRCP_PROGRESSION ? "LRCP" : (params.progression == RLCP_PROGRESSION ? "RLCP" : (params.progression == RPCL_PROGRESSION ? "RPCL" : (params.progression == PCRL_PROGRESSION ? "PCRL" : (params.progression == CPRL_PROGRESSION ? "CPRL" : "UNKOWN"))))) << endl << "Size: " << params.size << endl << "Num. of levels: " << params.num_levels << endl << "Num. of layers: " << params.num_layers << endl << "Num. of components: " << params.num_components << endl << "Precinct size: { "; for (vector::const_iterator i = params.precinct_size.begin(); i != params.precinct_size.end(); i++) out << *i << " "; out << "}" << endl; return out; } /** * Returns true if the progression is RLCP or RPCL. */ bool IsResolutionProgression() const { return ((progression == RLCP_PROGRESSION) || (progression == RPCL_PROGRESSION)); } /** * Returns a precinct coordinate adjusted to a given resolution level. * @param r Resolution level. * @param point Precinct coordinate. */ Size GetPrecincts(int r, const Size& point) { return Size( ceil(ceil((double)point.x / (1L << (num_levels - r))) / (double)precinct_size[r].x), ceil(ceil((double)point.y / (1L << (num_levels - r))) / (double)precinct_size[r].y) ); } /** * Returns the index of a packet according to the * progression order. * @param packet Packet information. */ int GetProgressionIndex(const Packet& packet) { if(total_precincts.size() == 0) FillTotalPrecinctsVector(); if(progression == RPCL_PROGRESSION) { return GetProgressionIndexRPCL(packet.layer, packet.resolution, packet.component, packet.precinct_xy.x, packet.precinct_xy.y); } else if(progression == RLCP_PROGRESSION) { return GetProgressionIndexRLCP(packet.layer, packet.resolution, packet.component, packet.precinct_xy.x, packet.precinct_xy.y); } else if(progression == LRCP_PROGRESSION) { return GetProgressionIndexLRCP(packet.layer, packet.resolution, packet.component, packet.precinct_xy.x, packet.precinct_xy.y); } else { ERROR("Progression (" << progression << ") not supported"); return 0; } } /** * Returns the data-bin identifier associated to the * given packet. * @param packet Packet information. */ int GetPrecinctDataBinId(const Packet& packet) { if(total_precincts.size() == 0) FillTotalPrecinctsVector(); Size precinct_point = GetPrecincts(packet.resolution, size); int s = total_precincts[packet.resolution] + (precinct_point.x * packet.precinct_xy.y) + packet.precinct_xy.x; return (packet.component + (s * num_components)); } /** * Returns the resolution level according to the given size and * the closest round policy. * @param res_size Resolution size. * @param res_image_size Image size associated to the * resolution level returned. */ int GetClosestResolution(const Size& res_size, Size *res_image_size); /** * Returns the resolution level according to the given size and * the round-up round policy. * @param res_size Resolution size. * @param res_image_size Image size associated to the * resolution level returned. */ int GetRoundUpResolution(const Size& res_size, Size *res_image_size); /** * Returns the resolution level according to the given size and * the round-down round policy. * @param res_size Resolution size. * @param res_image_size Image size associated to the * resolution level returned. */ int GetRoundDownResolution(const Size& res_size, Size *res_image_size); virtual ~CodingParameters() { } }; } #endif /* _JPEG2000_CODING_PARAMETERS_H_ */ esajpip-0.1~bzr33/src/jpeg2000/packet_index.cc0000644000175000017500000000003312335423210020713 0ustar mathieumathieu#include "packet_index.h" esajpip-0.1~bzr33/src/jpeg2000/range.h0000644000175000017500000000464112335423210017224 0ustar mathieumathieu#ifndef _JPEG2000_RANGE_H_ #define _JPEG2000_RANGE_H_ #include #include namespace jpeg2000 { using namespace std; /** * Represents a range of integer values, defined by * two values, first and last, which are assumed to * be included in the range. Some basic operations * are defined for easing the work with ranges. */ class Range { public: int first; ///< First value of the range int last; ///< Last value of the range /** * Initializes the object. */ Range() { first = 0; last = 0; } /** * Initializes the object. * @param first First value. * @param last Last value. */ Range(int first, int last) { assert((first >= 0) && (first <= last)); this->first = first; this->last = last; } /** * Copy constructor. */ Range(const Range& range) { *this = range; } /** * Copy assignment. */ Range& operator=(const Range& range) { first = range.first; last = range.last; return *this; } /** * Returns true if the first value if * greater or equal to zero, and it is less or * equal to the last value. */ bool IsValid() const { return ((first >= 0) && (first <= last)); } /** * Returns an item of the range, starting at the * first value. * @param i Item index. * @return first + i. */ int GetItem(int i) const { return (first + i); } /** * Returns the index of an item of the range. * @param item Item of the range. * @return item - first. */ int GetIndex(int item) const { return (item - first); } /** * Returns the length of the range (last - first + 1). */ int Length() const { return (last - first + 1); } friend bool operator==(const Range& a, const Range& b) { return ((a.first == b.first) && (a.last == b.last)); } friend bool operator!=(const Range& a, const Range& b) { return ((a.first != b.first) || (a.last != b.last)); } friend ostream& operator << (ostream &out, const Range &range) { if(range.IsValid()) out << "[" << range.first << " - " << range.last << "]"; else out << "[ ]"; return out; } virtual ~Range() { } }; } #endif /* _JPEG2000_RANGE_H_ */ esajpip-0.1~bzr33/src/jpeg2000/place_holder.cc0000644000175000017500000000003312335423210020676 0ustar mathieumathieu#include "place_holder.h" esajpip-0.1~bzr33/src/jpeg2000/index_manager.h0000644000175000017500000000601712335423210020730 0ustar mathieumathieu#ifndef _JPEG2000_INDEX_MANAGER_H_ #define _JPEG2000_INDEX_MANAGER_H_ #include #include "ipc/mutex.h" #include "image_index.h" #include "file_manager.h" namespace jpeg2000 { using namespace ipc; /** * Manages the indexing information of a repository fo images. * Maintains a list in memory of the indexes (using the class * ImageIndex for the nodes) of all the opened * images and allows a multi-thread access to the information. * * @see FileManager * @see ImageIndex */ class IndexManager { private: /** * Mutex for the operations with the list. */ Mutex mutex; FileManager file_manager_; ///< File manager list index_list; ///< List of the indexes /** * Unsafely (without mutex) opens an image and adds its index * to the list. * @param path_image_file Path of the image file. * @param image_index Receives the pointer to the image index created. * @return true if successful. */ bool UnsafeOpenImage(string &path_image_file, ImageIndex::Ptr *image_index); /** * Unsafely (without mutex) closes an image and removes its index * from the list, only if it is not used by any other one. * @param image_index Associated image index. * @return true if successful. */ bool UnsafeCloseImage(const ImageIndex::Ptr& image_index); public: /** * Empty constructor. */ IndexManager() { } /** * Initializes the object. * @param root_dir Root directory of the image repository. * @param cache_dir Directory used for caching. * @return true if successful */ bool Init(string root_dir, string cache_dir) { return file_manager_.Init(root_dir, cache_dir) && mutex.Init(false); } /** * Returns a pointer to the first image index. */ ImageIndex::Ptr GetBegin() { return index_list.begin(); } /** * Returns a pointer to the last image index. */ ImageIndex::Ptr GetEnd() { return index_list.end(); } /** * Returns a reference to the base file manager. */ FileManager& file_manager() { return file_manager_; } /** * Opens an image and adds its index to the list. * @param path_image_file Path of the image file. * @param image_index Receives the pointer to the image index created. * @return true if successful. */ bool OpenImage(string &path_image_file, ImageIndex::Ptr *image_index); /** * Closes an image and removes its index * from the list, only if it is not used by any other one. * @param image_index Associated image index. * @return true if successful. */ bool CloseImage(const ImageIndex::Ptr& image_index); /** * Returns the size of the list. */ int GetSize() const { return (int)index_list.size(); } virtual ~IndexManager() { } }; } #endif /* _JPEG2000_INDEX_MANAGER_H_ */ esajpip-0.1~bzr33/src/jpeg2000/file_manager.h0000644000175000017500000001412612335423210020540 0ustar mathieumathieu#ifndef _JPEG2000_FILE_MANAGER_H_ #define _JPEG2000_FILE_MANAGER_H_ #include #include "data/serialize.h" #include "image_info.h" namespace jpeg2000 { /** * Manages the image files of a repository, allowing read their * indexing information, with a caching mechanism for efficiency. */ class FileManager { private: string root_dir_; ///< Root directory of the repository string cache_dir_; ///< Caching directory /** * Returns true if the cache file exists and it is updated. * @param path_image_file Path of the image file. * @param path_cache_file Receives the path of the associated cache file. */ bool ExistCacheImage(const string& path_image_file, string *path_cache_file); /** * Reads the header information. of a JP2/JPX box. * @param fim Image file. * @param type_box Receives the type of the box. * @param length_box Receives the length of the box. * @return true if successful. */ bool ReadBoxHeader(const File &fim, uint32_t *type_box, uint64_t *length_box); /** * Reads the information of a codestream. * @param file Image file. * @param params Receives the coding parameters. * @param index Receives the indexing information. * @return true if successful. */ bool ReadCodestream(const File& file, CodingParameters *params, CodestreamIndex *index); /** * Reads the information of a SIZ marker. * @param file Image file. * @param params Pointer to the coding parameters to update. * @return true if successful. */ bool ReadSIZMarker(const File& file, CodingParameters *params); /** * Reads the information of a COD marker. * @param file Image file. * @param params Pointer to the coding parameters to update. * @return true if successful. */ bool ReadCODMarker(const File& file, CodingParameters *params); /** * Reads the information of a SOT marker. * @param file Image file. * @param index Pointer to the indexing information to update. * @return true if successful. */ bool ReadSOTMarker(const File& file, CodestreamIndex *index); /** * Reads the information of a PLT marker. * @param file Image file. * @param index Pointer to the indexing information to update. * @return true if successful. */ bool ReadPLTMarker(const File& file, CodestreamIndex *index); /** * Reads the information of a SOD marker. * @param file Image file. * @param index Pointer to the indexing information to update. * @return true if successful. */ bool ReadSODMarker(const File& file, CodestreamIndex *index); /** * Reads the information of a JP2 image file. * @param file Image file. * @param image_info Receives the image information. * @return true if successful. */ bool ReadJP2(const File& file, ImageInfo *image_info); /** * Reads the information of a JPX image file. * @param file Image file. * @param image_info Receives the image information. * @return true if successful. */ bool ReadJPX(const File& file, ImageInfo *image_info); /** * Reads the information of a NLST box. * @param file Image file. * @param num_codestream Receives the number of codestream read. * @param length_box Box length in bytes. * @return true if successful. */ bool ReadNlstBox(const File& file, int *num_codestream, int length_box); /** * Reads the information of a FLST box. * @param file Image file. * @param length_box Box length in bytes. * @param data_reference Receives the data reference. * @return true if successful. */ bool ReadFlstBox(const File& file, uint64_t length_box, uint16_t *data_reference); /** * Reads the information of a URL box. * @param file Image file. * @param length_box Box length in bytes. * @param path_file Receives the URL path read. * @return true if successful. */ bool ReadUrlBox(const File& file, uint64_t length_box, string *path_file); public: /** * Returns the cache file name equivalent to the given * image file name. */ string GetCacheFileName(const string& path_image_file); /** * Initializes the object. */ FileManager() { root_dir_ = "./"; cache_dir_ = "./"; } /** * Initializes the object. * @param root_dir Root directory of the image repository. * @param cache_dir Directory for caching. */ FileManager(string root_dir, string cache_dir) { assert(Init(root_dir, cache_dir)); } /** * Initializes the object. * @param root_dir Root directory of the image repository. * @param cache_dir Directory for caching. * @return true if successful */ bool Init(string root_dir = "./", string cache_dir = "./") { if((root_dir.size() == 0) || (cache_dir.size() == 0)) return false; else { root_dir_ = root_dir; cache_dir_ = cache_dir; if(root_dir_.at(root_dir_.size() - 1) != '/') root_dir_ += '/'; if(cache_dir_.at(cache_dir_.size() - 1) != '/') cache_dir_ += '/'; return true; } } /** * Returns the root directory of the image repository. */ string root_dir() const { return root_dir_; } /** * Returns the directory used for caching. */ string cache_dir() const { return cache_dir_; } /** * Reads an image file and creates the associated cache file if * it does not exist yet. * @param name_image_file File name of the image. * @param image_info Receives the information of the image. * @return true if successful. */ bool ReadImage(const string& name_image_file, ImageInfo *image_info); virtual ~FileManager() { } }; } #endif /* _JPEG2000_FILE_MANAGER_H_ */ esajpip-0.1~bzr33/src/jpeg2000/jpeg2000.h0000644000175000017500000000042012335423210017346 0ustar mathieumathieu#ifndef _JPEG2000_JPEG2000_H_ #define _JPEG2000_JPEG2000_H_ /** * Set of classes for handling (reading and indexing) image * files with the format defined in the Part 1 and 2 of the * JPEG2000 standard. */ namespace jpeg2000 { } #endif /* _JPEG2000_JPEG2000_H_ */ esajpip-0.1~bzr33/src/jpeg2000/coding_parameters.cc0000644000175000017500000000473312335423210021756 0ustar mathieumathieu#include "coding_parameters.h" namespace jpeg2000 { void CodingParameters::FillTotalPrecinctsVector() { int pa = 0; Size precinct_point; total_precincts.clear(); total_precincts.push_back(pa); for (int i = 0; i <= num_levels; i++) { precinct_point = GetPrecincts(i, size); pa += precinct_point.x * precinct_point.y; total_precincts.push_back(pa); } } int CodingParameters::GetClosestResolution(const Size& res_size, Size *res_image_size) { int distance, final_r = 0; int distance_x = size.x - res_size.x; int distance_y = size.y - res_size.y; int min = fabs(distance_x) + fabs(distance_y); int res_image_x, res_image_y; res_image_size->x=size.x; res_image_size->y=size.y; for (int r = 1; r <= num_levels; r++) { res_image_x=ceil((double)size.x / (double)(1L << r)); res_image_y=ceil((double)size.y / (double)(1L << r)); distance_x = res_image_x - res_size.x; distance_y = res_image_y - res_size.y; distance = fabs(distance_x) + fabs(distance_y); if (distance < min) { res_image_size->x=res_image_x; res_image_size->y=res_image_y; min = distance; final_r = r; } } int res = (num_levels - final_r); if(res > num_levels) res = num_levels; else if(res < 0) res = 0; return res; } int CodingParameters::GetRoundUpResolution(const Size& res_size, Size *res_image_size) { int r = num_levels; bool bigger = false; while ((!bigger) && (r >= 0)) { res_image_size->x=ceil((double)size.x / (double)(1L << r)); res_image_size->y=ceil((double)size.y / (double)(1L << r)); if ((res_image_size->x >= res_size.x) && (res_image_size->y >= res_size.y)) bigger = true; else r--; } int res = (num_levels - r); if(res > num_levels) res = num_levels; else if(res < 0) res = 0; return res; } int CodingParameters::GetRoundDownResolution(const Size& res_size, Size *res_image_size) { int r = 0; bool smaller = false; while ((!smaller) && (r <= num_levels)) { res_image_size->x=ceil((double)size.x / (double)(1L << r)); res_image_size->y=ceil((double)size.y / (double)(1L << r)); if ((res_image_size->x <= res_size.x) && (res_image_size->y <= res_size.y)) smaller = true; else r++; } int res = (num_levels - r); if(res > num_levels) res = num_levels; else if(res < 0) res = 0; return res; } } esajpip-0.1~bzr33/src/jpeg2000/packet.h0000644000175000017500000000272612335423210017401 0ustar mathieumathieu#ifndef _JPEG2000_PACKET_H_ #define _JPEG2000_PACKET_H_ #include "point.h" namespace jpeg2000 { /** * Contains the information of a packet. This * class can be printed. */ class Packet { public: int layer; ///< Quality layer. int component; ///< Component number. int resolution; ///< Resolution level. Point precinct_xy; ///< Precinct coordinate. /** * Initializes the object to zero. */ Packet() { layer = resolution = component = 0; } /** * Initializes the object. */ Packet(int layer, int resolution, int component, Point precinct_xy) { this->layer = layer; this->resolution = resolution; this->component = component; this->precinct_xy = precinct_xy; } /** * Copy constructor. */ Packet(const Packet& packet) { *this = packet; } /** * Copy assignment. */ const Packet& operator=(const Packet& packet) { layer = packet.layer; component = packet.component; resolution = packet.resolution; precinct_xy = packet.precinct_xy; return *this; } friend ostream& operator <<(ostream &out, const Packet &packet) { out << packet.layer << "\t" << packet.resolution << "\t" << packet.component << "\t" << packet.precinct_xy.y << "\t" << packet.precinct_xy.x; return out; } virtual ~Packet() { } }; } #endif /* _JPEG2000_PACKET_H_ */ esajpip-0.1~bzr33/src/jpeg2000/image_index.h0000644000175000017500000002211112335423210020371 0ustar mathieumathieu#ifndef _JPEG2000_INDEX_NODE_H_ #define _JPEG2000_INDEX_NODE_H_ //#define SHOW_TRACES #include "trace.h" #include #include #include "base.h" #include "range.h" #include "image_info.h" #include "packet_index.h" #include "ipc/rdwr_lock.h" namespace jpeg2000 { using namespace std; using namespace ipc; /** * Contains the indexing information of a JPEG2000 image file that * is managed by the index manager. This class can be printed. * * Maintains a read/write lock for controlling the multi-thread * access to the indexing information. For instance, by default * all the threads usually want to read the information. The * packet index built on demand, so only when a thread wants to * create a new level of the packet index, it needs to write. * * @see IndexManager */ class ImageIndex { private: friend class IndexManager; /** * Read/write lock. */ RdWrLock::Ptr rdwr_lock; vector last_plt; vector last_packet; vector last_offset_PLT; vector last_offset_packet; string path_name; ///< Image file name Metadata meta_data; ///< Image Metadata int num_references; ///< Number of references vector max_resolution; ///< Maximum resolution number vector packet_indexes; ///< Code-stream packet index vector codestreams; ///< Image code-streams CodingParameters::Ptr coding_parameters; ///< Image coding parameters vector::iterator> hyper_links; ///< Image hyperlinks /** * Gets the packet lengths from a PLT marker. * @param file File where to read the data from. * @param ind_codestream Codestream index. * @param length_packet It is returned the length of the packet. * @return true if successful. */ bool GetPLTLength(const File& file, int ind_codestream, uint64_t *length_packet); /** * Gets the packet offsets. * @param file File where to read the data from. * @param ind_codestream Codestream index. * @param length_packet Packet length. * @return true if successful. */ void GetOffsetPacket(const File& file, int ind_codestream, uint64_t length_packet); /** * Builds the required index for the required resolution levels. * @param ind_codestream Codestream index. * @param max_index Maximum resolution level. * @return true if successful */ bool BuildIndex(int ind_codestream, int max_index); /** * Initializes the object. * @param path_name Path name of the image. * @param image_info Indexing image information. * @return true if successful */ bool Init(const string& path_name, const ImageInfo& image_info); /** * Initializes the object. * @param path_name Path name of the image. * @param coding_parameters Coding parameters. * @param image_info Indexing image information. * @param index Image index. * @return true if successful */ bool Init(const string& path_name, CodingParameters::Ptr coding_parameters, const ImageInfo& image_info, int index); /** * Empty constructor. Only the index manager can * use this constructor. */ ImageIndex() { } public: /** * Pointer of an object of this class. */ typedef list::iterator Ptr; /** * Copy constructor. */ ImageIndex(const ImageIndex& image_index) { *this = image_index; } /** * Returns the number of codestreams. */ int GetNumCodestreams() const { if(codestreams.size() > 0) return codestreams.size(); else return hyper_links.size(); } /** * Returns the number of meta-data blocks. */ int GetNumMetadatas() const { return meta_data.meta_data.size(); } /** * Gets the lock for reading, for a specific range of * codestreams. * @return true if successful */ bool ReadLock(const Range& range = Range(0, 0)); /** * Releases the lock for reading, for a specific range of * codestreams. * @return true if successful */ bool ReadUnlock(const Range& range = Range(0, 0)); /** * Returns the path name of the image. */ string GetPathName() const { return path_name; } /** * Returns the path name of a given codestream, if it is * a hyperlinked codestream. * @param num_codestream Codestream number. */ string GetPathName(int num_codestream) const { if(codestreams.size() > 0) return path_name; else return hyper_links[num_codestream]->path_name; } /** * Returns the file segment the main header of a given * codestream. * @param num_codestream Codestream number */ FileSegment GetMainHeader(int num_codestream) const { if(codestreams.size() > 0) return codestreams[num_codestream].header; else return hyper_links[num_codestream]->codestreams.back().header; } /** * Returns the file segment of a meta-data block. * @param num_metadata Meta-data number. */ FileSegment GetMetadata(int num_metadata) const { return meta_data.meta_data[num_metadata]; } /** * Returns the information of a place-holder. * @param num_placeholder Place-holder number. */ PlaceHolder GetPlaceHolder(int num_placeholder) const { return meta_data.place_holders[num_placeholder]; } /** * Returns the file segment of a packet. * @param num_codestream Codestream number. * @param packet Packet information. * @param offset If it is not NULL receives the * offset of the packet. */ FileSegment GetPacket(int num_codestream, const Packet& packet, int *offset = NULL); /** * Returns a pointer to the coding parameters. */ CodingParameters::Ptr GetCodingParameters() const { return coding_parameters; } /** * Returns true if the image contains * hyperlinks. */ bool IsHyperLinked(int num_codestream) const { return (num_codestream < (int)hyper_links.size()); } /** * Returns a pointer to a hyperlink. * @param num_codestream Number of the hyperlink (codestream). */ Ptr GetHyperLink(int num_codestream) const { return hyper_links[num_codestream]; } /** * Returns the number of hyperlinks. */ int GetNumHyperLinks() const { return (int)hyper_links.size(); } operator CodingParameters::Ptr() const { return coding_parameters; } ImageIndex& operator=(const ImageIndex& image_index) { rdwr_lock = image_index.rdwr_lock; meta_data = image_index.meta_data; path_name = image_index.path_name; num_references = image_index.num_references; coding_parameters = image_index.coding_parameters; base::copy(max_resolution, image_index.max_resolution); base::copy(last_plt, image_index.last_plt); base::copy(last_packet, image_index.last_packet); base::copy(codestreams, image_index.codestreams); base::copy(hyper_links, image_index.hyper_links); base::copy(packet_indexes, image_index.packet_indexes); base::copy(last_offset_PLT, image_index.last_offset_PLT); base::copy(last_offset_packet, image_index.last_offset_packet); return *this; } friend ostream& operator <<(ostream &out, const ImageIndex &info_node) { out << "Image file name: " << info_node.path_name << endl << *(info_node.coding_parameters) << "Coding parameters ref: " << info_node.coding_parameters.use_count() << endl << "Max resolution: "; for (vector::const_iterator i = info_node.max_resolution.begin(); i != info_node.max_resolution.end(); i++) out << *i << " "; out << endl; for (vector::const_iterator i = info_node.codestreams.begin(); i != info_node.codestreams.end(); i++) out << "Codestream index: " << endl << "----------------- " << endl << *i << endl << endl; out << "Packet indexes: " << endl << "--------------- " << endl; for (vector::const_iterator i = info_node.packet_indexes.begin(); i != info_node.packet_indexes.end(); i++) for (int j = 0; j < i->Size(); j++) out << j << " - " << (*i)[j] << endl; out << endl << "Num. Hyperlinks: " << info_node.hyper_links.size() << endl; for (vector::iterator>::const_iterator i = info_node.hyper_links.begin(); i != info_node.hyper_links.end(); i++) out << "Hyperlinks: " << endl << "----------- " << endl << **i << endl << "----------- " << endl; out << endl << "Meta-data: "; out << endl << info_node.meta_data; out << endl << "Num. References: " << info_node.num_references << endl; return out; } virtual ~ImageIndex() { TRACE("Destroying the image index of '" << path_name << "'"); } }; } #endif /* _JPEG2000_INDEX_NODE_H_ */ esajpip-0.1~bzr33/src/app_info.cc0000644000175000017500000000676212335423210016640 0ustar mathieumathieu#include #include #include #include #include #include #include #include #include #include #include #include #ifndef _SC_AVPHYS_PAGES #include #endif #include "app_info.h" using namespace std; #define LOCK_FILE "/tmp/esa_jpip_server.lock" bool AppInfo::Init() { struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1; bool res = false; mode_t prevm = umask(0); if((lock_file = open(LOCK_FILE, O_WRONLY | O_CREAT, 0666)) != -1) { is_running_ = (fcntl(lock_file, F_SETLK, &fl) == -1); if((shmid = shmget(ftok(LOCK_FILE, 'c'), sizeof(Data), IPC_CREAT | 0666)) >= 0) { if((data_ptr = (Data *)shmat(shmid, NULL, 0)) != (Data *)-1) { if(!is_running_) data_ptr->Reset(); res = true; } } } umask(prevm); return res; } AppInfo& AppInfo::Update() { #if defined(_SC_AVPHYS_PAGES) { long page_size = sysconf(_SC_PAGE_SIZE); long avpages = sysconf(_SC_AVPHYS_PAGES); available_memory_ = (avpages * page_size / (1024.0 * 1024.0)); } #elif defined(HW_PHYSMEM) { unsigned int physmem; size_t len = sizeof(physmem); static int mib[2] = { CTL_HW, HW_PHYSMEM }; sysctl(mib, sizeof(mib) * sizeof(mib[0]), &physmem, &len, NULL, 0); available_memory_ = (double) physmem; } #endif { is_running_ = false; int lock; struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1; if((lock = open(LOCK_FILE, O_RDONLY, 0666)) != -1) { if(fcntl(lock, F_GETLK, &fl) != -1) is_running_ = (fl.l_type != F_UNLCK); close(lock); } } if(!is_running_) { father_memory_ = 0; child_memory_ = 0; child_time_ = 0; num_threads_ = 0; } else { #ifndef _NO_READPROC // field 22: vsize. Virtual memory size in bytes. double vsize = GetProcStat(data_ptr->father_pid, 22); father_memory_ = (vsize / (1024.0 * 1024.0)); // field 23: rss. Resident Set Size double rss = GetProcStat(data_ptr->child_pid, 23); child_memory_ = rss * 4096.0 / (1024 * 1024); // field 13: utime. Amount of time that this process has been scheduled // in user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)) unsigned long utime = GetProcStat(data_ptr->child_pid, 13); // field 14: stime. Amount of time that this process has been scheduled // in kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)) unsigned long stime = GetProcStat(data_ptr->child_pid, 14); child_time_ = utime + stime; // field 19: stime. Number of threads in this process (since Linux 2.6). num_threads_ = GetProcStat(data_ptr->child_pid, 19); #endif } { time_ = 0; string line, cpu; unsigned long t1, t2; ifstream fin("/proc/stat"); if(getline(fin, line)) { istringstream str(line); if(str >> cpu >> t1 >> t2) { time_ = t1 * t2; while(str >> t2) time_ += t2; } } } return *this; } AppInfo::~AppInfo() { } string AppInfo::GetProcStat_(int pid, int field) const { string row; stringstream file_name; file_name << "/proc/" << pid << "/stat"; ifstream fin(file_name.str().c_str()); for (int i = 0; fin.good(); i++) { fin >> row; if (i == field) break; } return row; } esajpip-0.1~bzr33/src/args_parser.cc0000644000175000017500000000731012335423210017343 0ustar mathieumathieu#include #include #include #include #include #include #include #include #include #ifndef _NO_DIRENT #include #endif #include "trace.h" #include "args_parser.h" using namespace std; bool ArgsParser::Parse(int argc, char **argv) { if(argc <= 1) return true; else { bool res = false; string argv1 = argv[1]; string argv2 = (argc > 2 ? argv[2] : ""); if(argv1 == "stop") { if(!app_info.is_running()) { CERR("The server is not running"); } else if(argc == 2) { kill(app_info->father_pid, SIGKILL); waitpid(app_info->father_pid, NULL, 0); kill(app_info->child_pid, SIGKILL); waitpid(app_info->child_pid, NULL, 0); } else if(argv2 == "child") { kill(app_info->child_pid, SIGKILL); waitpid(app_info->child_pid, NULL, 0); } else { CERR("Invalid command"); } } else if(argv1 == "debug") { if(!app_info.is_running()) { CERR("The server is not running"); } else { stringstream cmd; cmd << "echo continue > /tmp/gdb_command;gdb " << argv[0] << " " << (argv2 == "child" ? app_info->child_pid : app_info->father_pid) << " -x /tmp/gdb_command"; system(cmd.str().c_str()); } } else if(argv1 == "start") { res = true; } else if(argv1 == "status") { app_info.Update(); cout << app_info; } else if(argv1 == "record") { static float cpu = 0; unsigned long tm_after, tm_before; cout << "Time\t\t\t Alive?\tFree\tFather\tChild\tConns\tIters\tThreads\t%CPU" << endl; app_info.Update(); if(argv2 != "") TraceSystem::AppendToFile(argv2.c_str()); for(;;) { app_info.Update(); tm_before = app_info.child_time(); if(!app_info.is_running()) LOG("0" << "\t" << app_info.available_memory() << "\t0\t0\t0\t0\t0\t0"); else LOG("1" << setiosflags(ios::fixed) << "\t" << setprecision(2) << app_info.available_memory() << "\t" << app_info.father_memory() << "\t" << app_info.child_memory() << "\t" << app_info->num_connections << "\t" << app_info->child_iterations << "\t" << app_info.num_threads() << "\t" << setiosflags(ios::fixed) << cpu ); sleep(5); app_info.Update(); tm_after = app_info.child_time(); cpu = (tm_after - tm_before)/5.0; } } else if((argv1 == "clean") && (argv2 == "cache")) { int num = 0; long rbytes = 0; DIR *dir = NULL; dirent *dir_ent = NULL; if((dir = opendir(cfg.caching_folder().c_str())) != NULL) { struct stat file_stat; time_t now = time(NULL); while((dir_ent = readdir(dir)) != NULL) { string path = cfg.caching_folder() + dir_ent->d_name; if(path.rfind(".cache") == (path.size() - 6)) { if(!stat(path.c_str(), &file_stat)) { if(((now - file_stat.st_atime) > cfg.cache_max_time()) && (cfg.cache_max_time() >= 0)) { if(!unlink(path.c_str())) { rbytes += file_stat.st_size; num++; } } } } else if(path.rfind(".backup") == (path.size() - 7)) { if(!stat(path.c_str(), &file_stat)) { if(!unlink(path.c_str())) { rbytes += file_stat.st_size; num++; } } } } closedir(dir); } CERR("Removed " << num << " files from cache (" << rbytes << " bytes)"); } else { CERR("Invalid command"); } return res; } } esajpip-0.1~bzr33/src/app_config.h0000644000175000017500000000721712335423210017010 0ustar mathieumathieu#ifndef _APP_CONFIG_H_ #define _APP_CONFIG_H_ #include #include using namespace std; /** * Contains the configuration parameters of the * application. It is possible to load these * parameters from a configuration file. This * class can be printed. */ class AppConfig { private: int port_; ///< Listening port int logging_; ///< true if logs messages are allowed int log_requests_; ///< true if the client requests are logged string address_; ///< Listening address string images_folder_; ///< Directory for the images string caching_folder_; ///< Directory for the caching files string logging_folder_; ///< Directory for the logging files int max_chunk_size_; ///< Maximum chunk size int max_connections_; ///< Maximum number of connections int com_time_out_; ///< Connection time-out int cache_max_time_; ///< Maximum time for the cache files public: /** * Initializes the object with zero and empty values. */ AppConfig() { port_ = 0; logging_ = 0; address_ = ""; log_requests_ = 0; images_folder_ = ""; caching_folder_ = ""; logging_folder_ = ""; max_chunk_size_ = 0; max_connections_ = 0; cache_max_time_ = 0; com_time_out_ = -1; } /** * Loads the parameters from a configuration file. * @param file_name Configuration file. * @return true if successful. */ bool Load(const char *file_name); friend ostream& operator <<(ostream &out, const AppConfig &cfg) { out << "Configuration:" << endl; out << "\tListen at: " << cfg.address_ << ":" << cfg.port_ << endl; out << "\tFolders:" << endl; out << "\t\tImages: " << cfg.images_folder_ << endl; out << "\t\tCaching: " << cfg.caching_folder_ << endl; out << "\t\tLogging: " << cfg.logging_folder_ << endl; out << "\tConnections: " << endl; out << "\t\tMax. number: " << cfg.max_connections_ << endl; out << "\t\tMax. time-out: " << cfg.com_time_out() << endl; out << "\tGeneral:" << endl; out << "\t\tLogging: " << (cfg.logging_ == 1 ? "yes" : "no") << endl; out << "\t\tLog. requests: " << (cfg.log_requests_ == 1 ? "yes" : "no") << endl; out << "\t\tChunk max. size: "<< cfg.max_chunk_size_ << endl; return out; } /** * Returns the listening port. */ int port() const { return port_; } /** * Returns the listening address. */ string address() const { return address_; } /** * Returns the folder of the images. */ string images_folder() const { return images_folder_; } /** * Returns the folder used for caching. */ string caching_folder() const { return caching_folder_; } /** * Returns the folder used for the logging files. */ string logging_folder() const { return logging_folder_; } /** * Returns the maximum chunk size. */ int max_chunk_size() const { return max_chunk_size_; } /** * Returns the maximum number of connections. */ int max_connections() const { return max_connections_; } /** * Returns true if the logging messages are allowed. */ bool logging() const { return (logging_ == 1); } /** * Returns true if the client requests are logged. */ bool log_requests() const { return (log_requests_ == 1); } /** * Returns the connection time-out. */ int com_time_out() const { return com_time_out_; } /** * Returns the maximum time for the cache files in * seconds. */ int cache_max_time() const { return cache_max_time_; } virtual ~AppConfig() { } }; #endif /* _APP_CONFIG_H_ */ esajpip-0.1~bzr33/src/ipc/0000755000175000017500000000000012335423210015276 5ustar mathieumathieuesajpip-0.1~bzr33/src/ipc/rdwr_lock.cc0000644000175000017500000000375312335423210017603 0ustar mathieumathieu#include "rdwr_lock.h" #include #include #include #include using namespace std; namespace ipc { bool RdWrLock::Init() { assert(!IsValid()); bool res = false; pthread_rwlockattr_t rwlockAttr; pthread_rwlockattr_init(&rwlockAttr); pthread_rwlockattr_setpshared(&rwlockAttr, PTHREAD_PROCESS_PRIVATE); res = !pthread_rwlock_init(&rwlock, &rwlockAttr); pthread_rwlockattr_destroy(&rwlockAttr); if(res) IPCObject::Init(); return res; } WaitResult RdWrLock::Wait(int time_out) { assert(IsValid()); if(time_out <= -1) { if(pthread_rwlock_rdlock(&rwlock)) return WAIT_ERROR; else return WAIT_OBJECT; } else { int res; struct timespec delay = {0, 1000000}; while((res = pthread_rwlock_tryrdlock(&rwlock)) == EBUSY) { if(!time_out) return WAIT_TIMEOUT; else { nanosleep(&delay, NULL); time_out--; } } if(res) return WAIT_ERROR; else return WAIT_OBJECT; } } WaitResult RdWrLock::WaitForWriting(int time_out) { assert(IsValid()); if(time_out <= -1) { if(pthread_rwlock_wrlock(&rwlock)) return WAIT_ERROR; else return WAIT_OBJECT; } else { int res; struct timespec delay = {0, 1000000}; while((res = pthread_rwlock_trywrlock(&rwlock)) == EBUSY) { if(!time_out) return WAIT_TIMEOUT; else { nanosleep(&delay, NULL); time_out--; } } if(res) return WAIT_ERROR; else return WAIT_OBJECT; } } bool RdWrLock::Release() { assert(IsValid()); if(pthread_rwlock_unlock(&rwlock)) return false; else { //pthread_yield(); sched_yield(); return true; } } bool RdWrLock::Dispose() { if(!IsValid()) return true; else { Release(); if(pthread_rwlock_destroy(&rwlock)) return false; else { IPCObject::Dispose(); return true; } } } } esajpip-0.1~bzr33/src/ipc/event.h0000644000175000017500000000541312335423210016573 0ustar mathieumathieu#ifndef _IPC_EVENT_H_ #define _IPC_EVENT_H_ #include #include "ipc_object.h" namespace ipc { /** * IPC object that offers the functionality of an event * (Windows IPC object), implemented by means of a * combination of the pthread mutex and conditional * variables API. * * @see IPCObject */ class Event :public IPCObject { private: bool state; ///< Current activation state of the event bool manual_reset; ///< Indicates if the event reset is manual pthread_cond_t condv; ///< Conditional variable information pthread_mutex_t mutex; ///< Mutex information public: /** * Pointer to a Event object. */ typedef SHARED_PTR Ptr; /** * Initializes the object desactivated and with automatic reset. * @return true if successful. */ virtual bool Init() { return Init(false); } /** * Initializes the object. * @param manual_reset true if the reset is manual. * @param initial_state true if the initial state is * activated. * @return true if successful. */ bool Init(bool manual_reset, bool initial_state = false); /** * Performs a wait operation with the object to get it. * @param time_out Time out (infinite by default). * @return WAIT_OBJECT if successful, * WAIT_TIMEOUT if time out or * WAIT_ERROR is error. */ virtual WaitResult Wait(int time_out = -1); /** * Release the resources associated to the IPC object and * sets the internal status to false. * @return true if successful. */ virtual bool Dispose(); /** * Sets the state of the object. If it is activated * (with true) and the reset is manual, * all the threads waiting for the object will be * resumed. If the reset is not manual (automatic), * only one thread will be resumed and the state will * be set to false again. * @param new_state New state of the object. * @return true if successful. */ bool Set(bool new_state = true); /** * Returns the current activation state of the object. */ bool Get() const { return state; } /** * Generates the same result as if the event has automatic * reset and the Set method is called with * true, independently of the real reset type. * @return true if successful. */ bool Pulse(); /** * Desactivates the object. * @return true if successful. */ bool Reset() { return Set(false); } }; } #endif /* _IPC_EVENT_H_ */ esajpip-0.1~bzr33/src/ipc/mutex.h0000644000175000017500000000307212335423210016613 0ustar mathieumathieu#ifndef _IPC_MUTEX_H_ #define _IPC_MUTEX_H_ #include #include "ipc_object.h" namespace ipc { /** * IPC object that offers the functionality of a mutex, * implemented by means of the pthread mutex API. * * @see IPCObject */ class Mutex :public IPCObject { private: pthread_t locker; ///< Id. of the thread that locks the mutex pthread_mutex_t mutex; ///< Mutex information public: /** * Pointer to a Mutex object. */ typedef SHARED_PTR Ptr; /** * Initializes the object without locking the mutex. * @return true if successful. */ virtual bool Init() { return Init(false); } /** * Initializes the object. * @param initial_owner If true the mutex is locked. * @return true if successful. */ bool Init(bool initial_owner); /** * Performs a wait operation with the object to get it. * @param time_out Time out (infinite by default). * @return WAIT_OBJECT if successful, * WAIT_TIMEOUT if time out or * WAIT_ERROR is error. */ virtual WaitResult Wait(int time_out = -1); /** * Release the resources associated to the IPC object and * sets the internal status to false. * @return true if successful. */ virtual bool Dispose(); /** * Releases/unlocks the mutex. * @return true if successful. */ bool Release(); }; } #endif /* _IPC_MUTEX_H_ */ esajpip-0.1~bzr33/src/ipc/rdwr_lock.h0000644000175000017500000000317612335423210017444 0ustar mathieumathieu#ifndef _IPC_RDWR_LOCK_H_ #define _IPC_RDWR_LOCK_H_ #include #include "ipc_object.h" namespace ipc { /** * IPC object that offers the functionality of a read/write * lock, implemented by means of the pthread rwlock API. * * @see IPCObject */ class RdWrLock :public IPCObject { private: pthread_rwlock_t rwlock; ///< Read/write lock information public: /** * Pointer to a RdWrLock object. */ typedef SHARED_PTR Ptr; /** * Initializes the object. * @return true if successful. */ virtual bool Init(); /** * Performs a wait operation with the object to get it * for reading. * @param time_out Time out (infinite by default). * @return WAIT_OBJECT if successful, * WAIT_TIMEOUT if time out or * WAIT_ERROR is error. */ virtual WaitResult Wait(int time_out = -1); /** * Performs a wait operation with the object to get it * for writing. * @param time_out Time out (infinite by default). * @return WAIT_OBJECT if successful, * WAIT_TIMEOUT if time out or * WAIT_ERROR is error. */ WaitResult WaitForWriting(int time_out = -1); /** * Release the resources associated to the IPC object and * sets the internal status to false. * @return true if successful. */ virtual bool Dispose(); /** * Releases the lock. * @return true if successful. */ bool Release(); }; } #endif /* _IPC_RDWR_LOCK_H_ */ esajpip-0.1~bzr33/src/ipc/event.cc0000644000175000017500000000475512335423210016741 0ustar mathieumathieu#include #include #include #include "event.h" namespace ipc { bool Event::Init(bool manual_reset, bool initial_state) { assert(!IsValid()); bool res = false; pthread_mutexattr_t mutexAttr; pthread_mutexattr_init(&mutexAttr); pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE); pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_PRIVATE); if(!pthread_mutex_init(&mutex, &mutexAttr)) { if(!pthread_cond_init(&condv, NULL)) { this->manual_reset = manual_reset; state = initial_state; res = true; } } if(res) IPCObject::Init(); else { pthread_mutex_destroy(&mutex); pthread_cond_destroy(&condv); } pthread_mutexattr_destroy(&mutexAttr); return res; } WaitResult Event::Wait(int time_out) { assert(IsValid()); WaitResult res = WAIT_OBJECT; pthread_mutex_lock(&mutex); if(!state) { if(time_out <= -1) pthread_cond_wait(&condv, &mutex); else { struct timespec ts; #ifndef CLOCK_REALTIME gettimeofday((timeval *)&ts, NULL); ts.tv_sec += (time_out / 1000); #else clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += (time_out / 1000); ts.tv_nsec += (time_out % 1000) * 1000000; ts.tv_sec += (ts.tv_nsec / 1000000000); ts.tv_nsec %= 1000000000; #endif if(pthread_cond_timedwait(&condv, &mutex, &ts) == ETIMEDOUT) res = WAIT_TIMEOUT; } } else { if(!manual_reset) state = false; } pthread_mutex_unlock(&mutex); return res; } bool Event::Set(bool new_state) { assert(IsValid()); pthread_mutex_lock(&mutex); if(new_state) { if(!state) { if(!manual_reset) pthread_cond_signal(&condv); else { pthread_cond_broadcast(&condv); state = true; } } } else { if(manual_reset) state = false; } pthread_mutex_unlock(&mutex); return true; } bool Event::Pulse() { assert(IsValid()); pthread_mutex_lock(&mutex); if(!manual_reset) pthread_cond_signal(&condv); else pthread_cond_broadcast(&condv); pthread_mutex_unlock(&mutex); return true; } bool Event::Dispose() { if(!IsValid()) return true; else { Reset(); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&condv); IPCObject::Dispose(); return true; } } } esajpip-0.1~bzr33/src/ipc/ipc.h0000644000175000017500000000057212335423210016226 0ustar mathieumathieu#ifndef _IPC_IPC_H_ #define _IPC_IPC_H_ /** * Contains classes for working with the IPC mechanisms available * in Linux using the pthread library. These classes * have been implemented to offer an object-oriented mechanism * similar to the one offered by Windows, because of its simplicity * and flexibility. */ namespace ipc { } #endif /* _IPC_IPC_H_ */ esajpip-0.1~bzr33/src/ipc/ipc_object.h0000644000175000017500000000553512335423210017560 0ustar mathieumathieu#ifndef _IPC_OBJECT_H_ #define _IPC_OBJECT_H_ #include "tr1_compat.h" namespace ipc { /** * Enumeration of the possible values returned * when a wait operation is performed for an IPC * object. */ enum WaitResult { WAIT_OBJECT = 0, ///< Wait successful (object got) WAIT_TIMEOUT, ///< Time out WAIT_ERROR ///< Error }; /** * Class base of all the IPC classes that has the basic * operations (Init, Wait and * Dispose) to be overloaded. It has also * an internal boolean value to set the object status. * * For the IPC objects the Windows IPC philosophy has * been adopted because of its simplicity and flexibility. * Under this philosophy, the main operation that can be * performed to an IPC object is Wait, to wait * for getting the control of the object. Depending on * the type of the IPC object (mutex, event, etc.), the * meaning of "getting" the control of the object can be * different. */ class IPCObject { private: /** * Internal status of the object. As it is a private * member, the derived classes must use the methods * Init and Dispose to set * the value of this status. */ bool valid; public: /** * Pointer to an IPC object. */ typedef SHARED_PTR Ptr; /** * Initializes the internal status to false. */ IPCObject() { valid = false; } /** * Sets the internal status to true * @return true if successful. If it * is not overloaded, it always returns true * . */ virtual bool Init() { valid = true; return true; } /** * Performs a wait operation with the object to get it. * @param time_out Time out (infinite by default). * @return WAIT_OBJECT if successful, * WAIT_TIMEOUT if time out or * WAIT_ERROR is error. If it is not overloaded, * it always returns WAIT_ERROR. */ virtual WaitResult Wait(int time_out = -1) { return WAIT_ERROR; } /** * Returns true if the object is valid, * that is, the internal status value is true. */ bool IsValid() { return valid; } /** * Release the resources associated to the IPC object and * sets the internal status to false. * @return true if successful. If it is not * overloaded, it always returns true. */ virtual bool Dispose() { valid = false; return true; } /** * The desctructor calls the method Dispose. */ virtual ~IPCObject() { Dispose(); } }; } #endif /* _IPC_OBJECT_H_ */ esajpip-0.1~bzr33/src/ipc/ipc_object.cc0000644000175000017500000000003112335423210017700 0ustar mathieumathieu#include "ipc_object.h" esajpip-0.1~bzr33/src/ipc/mutex.cc0000644000175000017500000000337712335423210016761 0ustar mathieumathieu#include #include #include #include "mutex.h" namespace ipc { bool Mutex::Init(bool initial_owner) { assert(!IsValid()); bool res = false; pthread_mutexattr_t mutexAttr; pthread_mutexattr_init(&mutexAttr); pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE); pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_PRIVATE); if(!pthread_mutex_init(&mutex, &mutexAttr)) { if(initial_owner) res = (Wait() == WAIT_OBJECT); else res = true; } if(!res) pthread_mutex_destroy(&mutex); pthread_mutexattr_destroy(&mutexAttr); if(res) IPCObject::Init(); return res; } WaitResult Mutex::Wait(int time_out) { assert(IsValid()); if(time_out <= -1) { if(pthread_mutex_lock(&mutex)) return WAIT_ERROR; else { locker = pthread_self(); return WAIT_OBJECT; } } else { int res; struct timespec delay = {0, 1000000}; while((res = pthread_mutex_trylock(&mutex)) == EBUSY) { if(!time_out) return WAIT_TIMEOUT; else { nanosleep(&delay, NULL); time_out--; } } if(res) return WAIT_ERROR; else { locker = pthread_self(); return WAIT_OBJECT; } } } bool Mutex::Release() { assert(IsValid()); if(locker != pthread_self()) return false; else { if(pthread_mutex_unlock(&mutex)) return false; else { //pthread_yield(); sched_yield(); return true; } } } bool Mutex::Dispose() { if(!IsValid()) return true; else { Release(); if(pthread_mutex_destroy(&mutex)) return false; else { IPCObject::Dispose(); return true; } } } } esajpip-0.1~bzr33/src/data/0000755000175000017500000000000012335423210015434 5ustar mathieumathieuesajpip-0.1~bzr33/src/data/serialize.h0000644000175000017500000002436612335423210017607 0ustar mathieumathieu#ifndef _DATA_SERIALIZE_H_ #define _DATA_SERIALIZE_H_ #include #include #include #include #include "file.h" namespace data { using namespace std; /** * This struct identifies a basic input operator to be applied * to a File object. * * @see BaseStream * @see File */ struct InputOperator { /** * Returns the required file access for this operator. */ inline static const char *FileAccess() { return "rb"; } /** * Performs an input (read) serialization of bytes for a file. * @param file File to use for the operation. * @param ptr Pointer to the buffer where to store the bytes. * @param num_bytes Number of bytes to read from the file. * @return true if successful. */ inline static bool SerializeBytes(File& file, void *ptr, int num_bytes) { return file.Read(ptr, num_bytes); } }; /** * This struct identifies a basic output operator to be applied * to a File object. * * @see BaseStream * @see File */ struct OutputOperator { /** * Returns the required file access for this operator. */ inline static const char *FileAccess() { return "wb"; } /** * Performs an output (write) serialization of bytes for a file. * @param file File to use for the operation. * @param ptr Pointer to the buffer where to read the bytes. * @param num_bytes Number of bytes to write to the file. * @return true if successful. */ inline static bool SerializeBytes(File& file, void *ptr, int num_bytes) { return file.Write(ptr, num_bytes); } }; /** * This template is used as the base for the input/output stream classes. * Contains the basic functionality for the serialization with files, * composed by a file object and an internal status. This status is updated * with each operation and, in a sequence of serialization, this is * stopped just after this status is set to false. * * In order to have a type serializable, it must comply with one of these * requirements: i) to have implemented a "serializer" with the class * Serializer, or ii) to have defined a member method called * SerializeWith. * * The first option is useful for the basic types (int, float, etc.) and * for those classes already defined and that can not be modified. The * second option is more elegant for those classes that can be modified * specifically for serialization. * * The SerializeWith method must be defined as follows: * * * template T& SerializeWith(T& stream) * { * return (stream & member1 & member2 & ...); * } * * * @see Serializer * @see InputStream * @see OutputStream */ template class BaseStream { protected: File file_; ///< File used for the serialization bool result_; ///< Internal current status of the serialization public: /** * Initializes the status to false. */ BaseStream() { result_ = false; } /** * Opens a file for serialization. * @param file_name Path name of the file to open. * @return *this. */ StreamClass& Open(const char *file_name) { result_ = file_.Open(file_name, StreamOperator::FileAccess()); return (StreamClass&) (*this); } /** * Opens a file for serialization. * @param file_name Path name of the file to open. * @param access Access mode to use to open the file. * @return *this. */ StreamClass& Open(const char *file_name, const char *access) { result_ = file_.Open(file_name, access); return (StreamClass&) (*this); } /** * Closes the file of the serialization and * finish the serialization. */ StreamClass& Close() { file_.Close(); result_ = false; return (StreamClass&) (*this); } /** * Serializes a number of bytes. Depending on the stream operator * in the template, this serialization is either a read or a write * operation. * @param ptr Pointer to the buffer. * @param num_bytes Number of bytes. * @return *this. */ StreamClass& SerializeBytes(void *ptr, int num_bytes) { result_ = (result_ && StreamOperator::SerializeBytes(file_, ptr, num_bytes)); return (StreamClass&) (*this); } /** * This operator overloading is the key of the serialization * mechanism. */ template StreamClass& operator&(T& var) { return ((StreamClass&) (*this)).Serialize(var); } /** * Returns the internal serialization status. */ bool result() const { return result_; } /** * Return the internal serialization status. */ operator bool() const { return result_; } /** * The destructor automatically closes the file- */ virtual ~BaseStream() { file_.Close(); } }; class InputStream; class OutputStream; /** * This template class allows to define a "serializer". By default, * the basic serializer calls the method SerializeWith * of the objet to be serialized. * * In order to define a serializer of any other specific type, it is * required to define a specialization of this template class, and * redefine the methods Load and Save. * * @see BaseStream */ template struct Serializer { static InputStream& Load(InputStream& stream, T& var) { return var.SerializeWith(stream); } static OutputStream& Save(OutputStream& stream, T& var) { return var.SerializeWith(stream); } }; /** * Specialization of the BaseStream for input * serializations. * * @see BaseStream */ class InputStream: public BaseStream { public: template InputStream& Serialize(T& var) { return Serializer::Load(*this, var); } }; /** * Specialization of the BaseStream for output * serializations. * * @see BaseStream */ class OutputStream: public BaseStream { public: template OutputStream& Serialize(T& var) { return Serializer::Save(*this, var); } }; /** * Serializer for the bool type. * * @see Serializer */ template<> struct Serializer { static InputStream& Load(InputStream& stream, bool& var) { return stream.SerializeBytes(&var, sizeof(var)); } static OutputStream& Save(OutputStream& stream, bool& var) { return stream.SerializeBytes(&var, sizeof(var)); } }; /** * Serializer for the int type. * * @see Serializer */ template<> struct Serializer { static InputStream& Load(InputStream& stream, int& var) { return stream.SerializeBytes(&var, sizeof(var)); } static OutputStream& Save(OutputStream& stream, int& var) { return stream.SerializeBytes(&var, sizeof(var)); } }; /** * Serializer for the uint64_t type. * * @see Serializer */ template<> struct Serializer { static InputStream& Load(InputStream& stream, uint64_t& var) { return stream.SerializeBytes(&var, sizeof(var)); } static OutputStream& Save(OutputStream& stream, uint64_t& var) { return stream.SerializeBytes(&var, sizeof(var)); } }; /** * Serializer for the string class. * * @see Serializer */ template<> struct Serializer { static InputStream& Load(InputStream& stream, string& var) { int num = 0; if (stream.Serialize(num)) { var.clear(); if (num > 0) { var.reserve(num); char *buf = new char[num]; if (stream.SerializeBytes(buf, num)) var.append(buf, num); delete[] buf; } } return stream; } static OutputStream& Save(OutputStream& stream, string& var) { int num = var.size(); if (stream.Serialize(num)) stream.SerializeBytes((void *) var.c_str(), num); return stream; } }; /** * Serializer for the vector class. * * @see Serializer */ template struct Serializer< vector > { static InputStream& Load(InputStream& stream, vector& var) { T item; int num = 0; var.clear(); if (stream.Serialize(num)) { for (int i = 0; i < num; i++) { if (!stream.Serialize(item)) break; var.push_back(item); } } return stream; } static OutputStream& Save(OutputStream& stream, vector& var) { T item; int num = 0; num = var.size(); if (stream.Serialize(num)) { for (int i = 0; i < num; i++) { item = var[i]; if (!stream.Serialize(item)) break; } } return stream; } }; /** * Serializer for the multimap class. * * @see Serializer */ template<> struct Serializer< multimap > { static InputStream& Load(InputStream& stream, multimap& var) { string key; int value, num = 0; var.clear(); if (stream.Serialize(num)) { for (int i = 0; i < num; i++) { if ((!stream.Serialize(key)) || (!stream.Serialize(value))) break; var.insert(pair (key, value)); } } return stream; } static OutputStream& Save(OutputStream& stream, multimap& var) { string key; int value, num = 0; num = var.size(); if (stream.Serialize(num)) { for (multimap::const_iterator i = var.begin(); i != var.end(); i++) { key = (*i).first; value = (*i).second; if ((!stream.Serialize(key)) || (!stream.Serialize(value))) break; } } return stream; } }; } #endif /* _DATA_SERIALIZE_H_ */ esajpip-0.1~bzr33/src/data/data.h0000644000175000017500000000031412335423210016514 0ustar mathieumathieu#ifndef _DATA_DATA_H_ #define _DATA_DATA_H_ /** * Contains a set of classes to easy the handling of data and * files, as well as the serialization. */ namespace data { } #endif /* _DATA_DATA_H_ */ esajpip-0.1~bzr33/src/data/vint_vector.cc0000644000175000017500000000003212335423210020300 0ustar mathieumathieu#include "vint_vector.h" esajpip-0.1~bzr33/src/data/file.cc0000644000175000017500000000002312335423210016655 0ustar mathieumathieu#include "file.h" esajpip-0.1~bzr33/src/data/file_segment.cc0000644000175000017500000000013612335423210020404 0ustar mathieumathieu#include "file_segment.h" namespace data { const FileSegment FileSegment::Null(0, 0); } esajpip-0.1~bzr33/src/data/serialize.cc0000644000175000017500000000003012335423210017723 0ustar mathieumathieu#include "serialize.h" esajpip-0.1~bzr33/src/data/file.h0000644000175000017500000002473612335423210016540 0ustar mathieumathieu#ifndef _DATA_FILE_H_ #define _DATA_FILE_H_ #include #include #include #include #include #include #include #ifndef _NO_FAST_FILE #include #endif #include "tr1_compat.h" namespace data { using namespace std; /** * Struct for wrapping the basic FILE locked functions for * reading and writing defined in stdio.h. * * @see File */ struct LockedAccess { static inline void configure(FILE *file_ptr) { } static inline size_t fwrite(const void *ptr, size_t size, size_t count, FILE *file_ptr) { return ::fwrite(ptr, size, count, file_ptr); } static inline size_t fread(void * ptr, size_t size, size_t count, FILE *file_ptr) { return ::fread(ptr, size, count, file_ptr); } static inline int fgetc(FILE *file_ptr) { return ::fgetc(file_ptr); } static inline int fputc(int c, FILE *file_ptr) { return ::fputc(c, file_ptr); } }; /** * Struct for wrapping the basic FILE unlocked functions for * reading and writing defined in stdio_exts.h. * * @see File */ #ifndef _NO_FAST_FILE struct UnlockedAccess { static inline void configure(FILE *file_ptr) { __fsetlocking(file_ptr, FSETLOCKING_BYCALLER); } static inline size_t fwrite(const void *ptr, size_t size, size_t count, FILE *file_ptr) { return ::fwrite_unlocked(ptr, size, count, file_ptr); } static inline size_t fread(void * ptr, size_t size, size_t count, FILE *file_ptr) { return ::fread_unlocked(ptr, size, count, file_ptr); } static inline int fgetc(FILE *file_ptr) { return ::fgetc_unlocked(file_ptr); } static inline int fputc(int c, FILE *file_ptr) { return ::fputc_unlocked(c, file_ptr); } }; #endif /** * This is a wrapper class for the FILE functions that * provides all the functionality to handle files safely. It is defined * as a template in order to allow to use either the locked or the * unlocked API, by means of the structs LockedAccess and * UnlockedAccess. The unlocked API is not thread-safe, * but it provides faster file operations. * * @see LockedAccess * @see UnlockedAccess */ template class BaseFile { public: /** * Safe pointer to this class. */ typedef SHARED_PTR< BaseFile > Ptr; /** * Initialized the internal file pointer to NULL. */ BaseFile() { file_ptr = NULL; } /** * Returns true if the given file exists. This * is a wrapper of the system funcion stat. */ static bool Exists(const char *file_name) { struct stat file_stat; return (stat(file_name, &file_stat) == 0); } /** * Opens a file with a specific access mode. * @param file_name Path name of the file to open. * @param access Access mode as a fopen * compatible format string. * @return true if successful. */ bool Open(const char *file_name, const char *access) { assert(file_ptr == NULL); if((file_ptr = fopen(file_name, access)) == NULL) return false; else { IO::configure(file_ptr); return true; } } /** * Opens a file with a specific access mode. * @param file_name Path name of the file to open. * @param access Access mode as a fopen * compatible format string. * @return true if successful. */ bool Open(const string& file_name, const char *access) { return Open(file_name.c_str(), access); } /** * Opens a file with a specific access mode given an already * opened File object. The descriptor of the opened * file is duplicated and re-opened with the access mode given. * @param file Opened file. * @param access Access mode as a fopen * compatible format string. * @return true if successful. */ template bool Open(const BaseFile& file, const char *access) { assert((file_ptr == NULL) && file.IsValid()); int new_fd = -1; if((new_fd = dup(file.GetDescriptor())) < 0) return false; else { if((file_ptr = fdopen(new_fd, access)) == NULL) { close(new_fd); return false; } else { IO::configure(file_ptr); return true; } } } /* * Calls the function Open with the "rb" * access mode (reading). */ bool OpenForReading(const char *file_name) { return Open(file_name, "rb"); } /* * Calls the function Open with the "rb" * access mode (reading). */ bool OpenForReading(const string& file_name) { return Open(file_name.c_str(), "rb"); } /* * Calls the function Open with the "rb" * access mode (reading). */ template bool OpenForReading(const BaseFile& file) { return Open(file, "rb"); } /* * Calls the function Open with the "wb" * access mode (writing). */ bool OpenForWriting(const char *file_name) { return Open(file_name, "wb"); } /* * Calls the function Open with the "wb" * access mode (writing). */ bool OpenForWriting(const string& file_name) { return Open(file_name.c_str(), "wb"); } /* * Calls the function Open with the "wb" * access mode (writing). */ template bool OpenForWriting(const BaseFile& file) { return Open(file, "wb"); } /** * Changes the current position of the file. * @param offset Offset to add to the current position. * @param origin Origin to use for the change ( * SEEK_SET by default). * @return true if successful. */ bool Seek(int offset, int origin = SEEK_SET) const { assert(file_ptr != NULL); return !fseek(file_ptr, offset, origin); } /** * Closes the file. */ void Close() { if(file_ptr != NULL) { fclose(file_ptr); file_ptr = NULL; } } /** * Returns the current file position. */ uint64_t GetOffset() const { assert(file_ptr != NULL); return ftell(file_ptr); } /** * Returns the EOF status (feof) of the file. */ int IsEOF() const { assert(file_ptr != NULL); return feof(file_ptr); } /** * Returns the file descriptor. */ int GetDescriptor() const { assert(file_ptr != NULL); return fileno(file_ptr); } /** * Return the current size of the file, without modifying * the file position. */ uint64_t GetSize() const { assert(file_ptr != NULL); uint64_t offset = GetOffset(); Seek(0, SEEK_END); uint64_t final_offset = GetOffset(); Seek(offset, SEEK_SET); return final_offset; } /** * Reads a byte from the file. */ int ReadByte() const { assert(file_ptr != NULL); return IO::fgetc(file_ptr); } /** * Reads a value from the file. * @param value Pointer to the value where to store. * @param num_bytes Number of bytes to read (by default, * the size of the value). * @return true if successful. */ template bool Read(T *value, int num_bytes = sizeof(T)) const { assert(file_ptr != NULL); return (IO::fread((void *) value, num_bytes, 1, file_ptr) == 1); } /** * Reads a value from the file in reverse order. * @param value Pointer to the value where to store. * @param num_bytes Number of bytes to read (by default, * the size of the value). * @return true if successful. */ template bool ReadReverse(T *value, int num_bytes = sizeof(T)) const { assert(file_ptr != NULL); for (char *ptr = ((char *) value) + (num_bytes - 1); num_bytes-- > 0; ptr--) if (IO::fread((void *) ptr, 1, 1, file_ptr) != 1) return false; return true; } /** * Writes a byte to the file. */ int WriteByte(int c) const { assert(file_ptr != NULL); return IO::fputc(c, file_ptr); } /** * Writes a value to the file. * @param value Pointer to the value. * @param num_bytes Number of bytes to write (by default, * the size of the value). * @return true if successful. */ template bool Write(T *value, int num_bytes = sizeof(T)) const { assert(file_ptr != NULL); return (IO::fwrite((void *) value, num_bytes, 1, file_ptr) == 1); } /** * Writes a value to the file in reverse order. * @param value Pointer to the value. * @param num_bytes Number of bytes to write (by default, * the size of the value). * @return true if successful. */ template bool WriteReverse(T *value, int num_bytes = sizeof(T)) const { assert(file_ptr != NULL); for (char *ptr = ((char *) value) + (num_bytes - 1); num_bytes-- > 0; ptr--) if (IO::fwrite((void *) ptr, 1, 1, file_ptr) != 1) return false; return true; } /** * Returns true if the file pointer is not * NULL. */ bool IsValid() const { return (file_ptr != NULL); } /** * Returns true if the file pointer is not * NULL. */ operator bool() const { return (file_ptr != NULL); } /** * The destructor closes the file. */ virtual ~BaseFile() { Close(); } private: /** * File pointer. */ FILE *file_ptr; }; /** * Specialization of the class BaseFile with * locked access. * * @see BaseFile * @see LockedAccess */ typedef BaseFile File; /** * Specialization of the class BaseFile with * unlocked access. * * @see BaseFile * @see UnlockedAccess */ #ifndef _NO_FAST_FILE typedef BaseFile FastFile; #endif } #endif /* _DATA_FILE_H_ */ esajpip-0.1~bzr33/src/data/vint_vector.h0000644000175000017500000000675712335423210020166 0ustar mathieumathieu#ifndef _DATA_VINT_VECTOR_H_ #define _DATA_VINT_VECTOR_H_ #include #include #include #include namespace data { using namespace std; /** * This class has been implemented with the same philosophy that the * class STL vector, but specifically designed to store integers * with a length in bytes that can be not multiple from 2 (e.g. integers * of 3 bytes). This class internally handles a vector of 1-byte integers. * * @see vector */ class vint_vector { private: uint64_t mask; ///< Mask used for accessing the data int8_t num_bytes_; ///< Number of bytes used for the integers vector data; //< Internal vector used for the data public: /** * Initializes the vector to store 64-bit integers. */ vint_vector() { set_num_bytes(sizeof(uint64_t)); } /** * Initializes the vector to store integers with the * number of bytes given as parameter. * @param num_bytes Number of bytes of each integer. */ vint_vector(int num_bytes) { set_num_bytes(num_bytes); } /** * Copy constructor. */ vint_vector(const vint_vector& v) { *this = v; } /** * Copy assignment. */ const vint_vector& operator=(const vint_vector& v) { mask = v.mask; num_bytes_ = v.num_bytes_; data.clear(); for(vector::const_iterator i = v.data.begin(); i != v.data.end(); i++) data.push_back(*i); return *this; } /** * Changes the number of bytes of the integer values. All the * current content is removed. * @param num_bytes New number of bytes to use. */ void set_num_bytes(int num_bytes) { assert((num_bytes >= 1) && (num_bytes <= (int)sizeof(uint64_t))); data.clear(); num_bytes_ = (int8_t)num_bytes; mask = 0xFF; while(--num_bytes > 0) mask = ((mask << 8) | 0xFF); } /** * Returns the number of bytes used. */ int num_bytes() const { return (int)num_bytes_; } /** * Returns the current number of bytes stored. */ int data_bytes() const { return (int)data.size(); } /** * Operator overloading for indexing the integer values. * @param index Index of the item to return. * @return Value of the item, always as a uint64_t. */ uint64_t operator[](int index) const { assert(((index * num_bytes_) + sizeof(uint64_t)) <= data.size()); return (*((uint64_t *)&(data[index * (int)num_bytes_])) & mask); } /** * Adds a new item to the end of the vector. * @param value Value to add to the vector. */ void push_back(uint64_t value) { data.insert(data.end(), data.size() <= 0 ? sizeof(uint64_t) : (int)num_bytes_, 0); *((uint64_t *)&(data[data.size() - sizeof(uint64_t)])) = value; } /** * Clears the content. */ void clear() { data.clear(); } /** * Returns the size of the vector, in number of items. */ int size() const { return max(0, (((int)data.size() - (int)sizeof(uint64_t)) / (int)num_bytes_) + 1); } /** * Return the reference of the last item of the vector. */ uint64_t& back() { assert(data.size() >= sizeof(uint64_t)); return *((uint64_t *)&(data[data.size() - sizeof(uint64_t)])); } virtual ~vint_vector() { } }; } #endif /* _DATA_VINT_VECTOR_H_ */ esajpip-0.1~bzr33/src/data/file_segment.h0000644000175000017500000000630712335423210020254 0ustar mathieumathieu#ifndef _DATA_FILE_SEGMENT_H_ #define _DATA_FILE_SEGMENT_H_ #include #include #include namespace data { using namespace std; /** * Identifies a data segment of a file. This segment is defined by an offset * and a length (number of bytes), both of them with an unsigned integer of * 64 bits. This class is serializable and can be printed. */ class FileSegment { public: uint64_t offset; ///< Offset of the data segment. uint64_t length; ///< Length of the data segment. /** * Identifies a null segment, with the offset as well as the length * set to zero. */ static const FileSegment Null; /** * Initializes all the member variables with zero, being a * null segment. */ FileSegment() { offset = length = 0; } /** * Initializes the segment with the given parameters. * @param offset Offset of the segment. * @param length Length of the segment. */ FileSegment(uint64_t offset, uint64_t length) { this->offset = offset; this->length = length; } /** * Copy constructor. */ FileSegment(const FileSegment& segment) { *this = segment; } /** * Copy assignment. */ FileSegment& operator=(const FileSegment& segment) { offset = segment.offset; length = segment.length; return *this; } /** * Removes the first bytes of the segment. Modifies the segment as * if a number of bytes (specified by the parameter) was removed * from the beginning of the segment. * @param count Number of bytes to remove. * @return *this. */ FileSegment& RemoveFirst(int count) { assert((length - count) >= 0); offset += count; length -= count; return *this; } /** * Removes the last bytes of the segment. Modifies the segment as * if a number of bytes (specified by the parameter) was removed * from the end of the segment. * @param count Number of bytes to remove. * @return *this. */ FileSegment& RemoveLast(int count) { assert((length - count) >= 0); length -= count; return *this; } /** * Returns true if the segment is contiguous to * another given segment, so the first byte of the given segment * is just the next byte after the last byte of the segment. */ bool IsContiguousTo(const FileSegment& segment) const { return ((offset + length) == segment.offset); } bool operator==(const FileSegment& segment) const { return ((offset == segment.offset) && (length == segment.length)); } bool operator!=(const FileSegment& segment) const { return ((offset != segment.offset) || (length != segment.length)); } template T& SerializeWith(T& stream) { return (stream & offset & length); } friend ostream& operator << (ostream &out, const FileSegment &segment) { out << "[" << segment.offset << ":" << segment.length << "]"; return out; } virtual ~FileSegment() { } }; } #endif /* _DATA_FILE_SEGMENT_H_ */ esajpip-0.1~bzr33/src/trace.cc0000644000175000017500000000253512335423210016135 0ustar mathieumathieu#include "trace.h" using namespace std; TraceSystem TraceSystem::traceSystem; TraceSystem::TraceSystem() { #ifndef SILENT_MODE layout = new log4cpp::PatternLayout(); layout->setConversionPattern("%d: %m %n"); appender = new log4cpp::OstreamAppender("OstreamAppender", &cout); appender->setLayout(layout); category = &(log4cpp::Category::getInstance("Category")); category->setPriority(log4cpp::Priority::DEBUG); category->setAppender(appender); file_appender = NULL; #endif } bool TraceSystem::AppendToFile_(const char *name) { #ifdef SILENT_MODE return true; #else if(file_appender) return false; else { char tm_cad[20] = ""; char fn_cad[200] = ""; time_t t; struct tm *tmp; t = time(NULL); tmp = localtime(&t); if(tmp == NULL) return false; else { if(!strftime(tm_cad, sizeof(tm_cad), "%Y%m%d.%H%M%S", tmp)) return false; else { snprintf(fn_cad, sizeof(fn_cad), "%s.%s.log", name, tm_cad); file_layout = new log4cpp::PatternLayout(); file_layout->setConversionPattern("%d: %m %n"); file_appender = new log4cpp::FileAppender("FileAppender", fn_cad); file_appender->setLayout(file_layout); category->setAppender(file_appender); return true; } } } #endif } TraceSystem::~TraceSystem() { log4cpp::Category::shutdown(); } esajpip-0.1~bzr33/src/app_config.cc0000644000175000017500000000247212335423210017144 0ustar mathieumathieu#include #include "app_config.h" using namespace std; using namespace libconfig; bool AppConfig::Load(const char *file_name) { try { int n; Config cfg; cfg.readFile(file_name); const Setting& root = cfg.getRoot(); root["listen_at"].lookupValue("port", port_); root["listen_at"].lookupValue("address", address_); root["folders"].lookupValue("images", images_folder_); root["folders"].lookupValue("caching", caching_folder_); root["folders"].lookupValue("logging", logging_folder_); if((n = images_folder_.size()) != 0) { if(images_folder_[n - 1] != '/') images_folder_ += '/'; } if((n = caching_folder_.size()) != 0) { if(caching_folder_[n - 1] != '/') caching_folder_ += '/'; } if((n = logging_folder_.size()) != 0) { if(logging_folder_[n - 1] != '/') logging_folder_ += '/'; } root["connections"].lookupValue("time_out", com_time_out_); root["connections"].lookupValue("max_number", max_connections_); root["general"].lookupValue("logging", logging_); root["general"].lookupValue("log_requests", log_requests_); root["general"].lookupValue("max_chunk_size", max_chunk_size_); root["general"].lookupValue("cache_max_time", cache_max_time_); } catch (...) { return false; } return true; } esajpip-0.1~bzr33/src/http/0000755000175000017500000000000012335423210015502 5ustar mathieumathieuesajpip-0.1~bzr33/src/http/header.h0000644000175000017500000001116512335423210017107 0ustar mathieumathieu#ifndef _HTTP_HEADER_H_ #define _HTTP_HEADER_H_ #include #include #include #include "protocol.h" namespace http { /** * Container for the strings associated to the most * common HTTP headers, used for the specialization of * the class HeaderBase. * * @see HeaderBase */ class HeaderName { public: static const char UNDEFINED[]; ///< No header name defined static const char CONTENT_TYPE[]; ///< The header Content-Type static const char CACHE_CONTROL[]; ///< The header Cache-Control static const char CONTENT_LENGTH[]; ///< The header Content-Length static const char TRANSFER_ENCODING[]; ///< The header Transfer-Encoding }; /** * Template class used to identify a HTTP header. It is * possible to use this class with standard streams. This * class is specialized with the header name. * * @see Header */ template class HeaderBase { private: string value; ///< String value of the header public: /** * Empty constructor. */ HeaderBase() { } /** * Initializes the header value. */ HeaderBase(const string& value) { this->value = value; } friend ostream& operator << (ostream &out, const HeaderBase &header) { return out << NAME << ": " << header.value << Protocol::CRLF; } friend istream& operator >> (istream &in, HeaderBase &header) { assert(0); in.setstate(istream::failbit); return in; } /** * Returns the name of the header, used in the specialization * of the class. */ static const char *name() { return NAME; } }; /** * Specialization of the HeaderBase template class * with the HeaderName::UNDEFINED value. In this case * the header name is not fixed, handled by an internal variable. * This class is used as base for the class Header. * * @see Header */ template<> class HeaderBase { public: string name; ///< Header name string value; ///< Header value /** * Empty constructor. */ HeaderBase() { } /** * Initializes the header content (name and value). * @param name Header name. * @param value Header value. */ HeaderBase(const string& name, const string& value) { this->name = name; this->value = value; } friend ostream& operator << (ostream &out, const HeaderBase &header) { return out << header.name << ": " << header.value << Protocol::CRLF; } friend istream& operator >> (istream &in, HeaderBase &header) { string line; if(getline(in, line)) { size_t line_size = line.size(); if(line_size <= 0) in.setstate(istream::eofbit); else if((line[0] == '\r') || (line[0] == '\n')) in.setstate(istream::eofbit); else { size_t pos = line.find(':'); if(pos == string::npos) in.setstate(istream::failbit); else { header.name = line.substr(0, pos); if((pos += 2) >= line_size) in.setstate(istream::failbit); else header.value = line.substr(pos, line_size - pos - 1); } } } return in; } }; /** * Class used to handle a HTTP header. * * @see HeaderBase * @see HeaderName */ class Header :public HeaderBase { public: /** * Predefined "Content-Type" */ typedef HeaderBase ContentType; /** * Predefined "Cache-Control" header. */ typedef HeaderBase CacheControl; /** * Predefined "Content-Length" header. */ typedef HeaderBase ContentLength; /** * Predefined "Transfer-Encoding" header. */ typedef HeaderBase TransferEncoding; /** * Empty constructor. */ Header() :HeaderBase() { } /** * Initializes the header content (name and value). * @param name Header name. * @param value Header value. */ Header(const string& name, const string& value) :HeaderBase(name, value) { } /** * Returns true if the names of the two headers are equal. */ template friend bool operator==(const Header& a, const HeaderBase& b) { return (strcasecmp(a.name.c_str(), b.name()) == 0); } }; } #endif /* _HTTP_HEADER_H_ */ esajpip-0.1~bzr33/src/http/header.cc0000644000175000017500000000051612335423210017243 0ustar mathieumathieu#include "header.h" namespace http { const char HeaderName::UNDEFINED[] = ""; const char HeaderName::CONTENT_TYPE[] = "Content-Type"; const char HeaderName::CACHE_CONTROL[] = "Cache-Control"; const char HeaderName::CONTENT_LENGTH[] = "Content-Length"; const char HeaderName::TRANSFER_ENCODING[] = "Transfer-Encoding"; } esajpip-0.1~bzr33/src/http/protocol.cc0000644000175000017500000000012512335423210017650 0ustar mathieumathieu#include "protocol.h" namespace http { const char Protocol::CRLF[] = "\r\n"; } esajpip-0.1~bzr33/src/http/response.cc0000644000175000017500000000642312335423210017654 0ustar mathieumathieu#include "response.h" namespace http { map Response::StatusCodes; Response::StatusCodesInitializer Response::statusCodesInitializer; Response::StatusCodesInitializer::StatusCodesInitializer() { Response::StatusCodes[100] = "Continue"; Response::StatusCodes[101] = "Switching Protocols"; Response::StatusCodes[102] = "Processing (WebDAV) (RFC 2518)"; Response::StatusCodes[200] = "OK"; Response::StatusCodes[201] = "Created"; Response::StatusCodes[202] = "Accepted"; Response::StatusCodes[203] = "Non-Authoritative Information (since HTTP/1.1)"; Response::StatusCodes[204] = "No Content"; Response::StatusCodes[205] = "Reset Content"; Response::StatusCodes[206] = "Partial Content"; Response::StatusCodes[207] = "Multi-Status (WebDAV) (RFC 4918)"; Response::StatusCodes[300] = "Multiple Choices"; Response::StatusCodes[301] = "Moved Permanently"; Response::StatusCodes[302] = "Found"; Response::StatusCodes[303] = "See Other (since HTTP/1.1)"; Response::StatusCodes[304] = "Not Modified"; Response::StatusCodes[305] = "Use Proxy (since HTTP/1.1)"; Response::StatusCodes[306] = "Switch Proxy"; Response::StatusCodes[307] = "Temporary Redirect (since HTTP/1.1)"; Response::StatusCodes[400] = "Bad Request"; Response::StatusCodes[401] = "Unauthorized"; Response::StatusCodes[402] = "Payment Required"; Response::StatusCodes[403] = "Forbidden"; Response::StatusCodes[404] = "Not Found"; Response::StatusCodes[405] = "Method Not Allowed"; Response::StatusCodes[406] = "Not Acceptable"; Response::StatusCodes[407] = "Proxy Authentication Required[2]"; Response::StatusCodes[408] = "Request Timeout 409 Conflict"; Response::StatusCodes[410] = "Gone"; Response::StatusCodes[411] = "Length Required"; Response::StatusCodes[412] = "Precondition Failed"; Response::StatusCodes[413] = "Request Entity Too Large"; Response::StatusCodes[414] = "Request-URI Too Long"; Response::StatusCodes[415] = "Unsupported Media Type"; Response::StatusCodes[416] = "Requested Range Not Satisfiable"; Response::StatusCodes[417] = "Expectation Failed"; Response::StatusCodes[418] = "I'm a teapot"; Response::StatusCodes[422] = "Unprocessable Entity (WebDAV) (RFC 4918)"; Response::StatusCodes[423] = "Locked (WebDAV) (RFC 4918)"; Response::StatusCodes[424] = "Failed Dependency (WebDAV) (RFC 4918)"; Response::StatusCodes[425] = "Unordered Collection (RFC 3648)"; Response::StatusCodes[426] = "Upgrade Required (RFC 2817)"; Response::StatusCodes[449] = "Retry With"; Response::StatusCodes[450] = "Blocked by Windows Parental Controls"; Response::StatusCodes[500] = "Internal Server Error"; Response::StatusCodes[501] = "Not Implemented"; Response::StatusCodes[502] = "Bad Gateway"; Response::StatusCodes[503] = "Service Unavailable"; Response::StatusCodes[504] = "Gateway Timeout"; Response::StatusCodes[505] = "HTTP Version Not Supported"; Response::StatusCodes[506] = "Variant Also Negotiates (RFC 2295)"; Response::StatusCodes[507] = "Insufficient Storage (WebDAV) (RFC 4918)[4]"; Response::StatusCodes[509] = "Bandwidth Limit Exceeded (Apache bw/limited extension)"; Response::StatusCodes[510] = "Not Extended (RFC 2774)"; } } esajpip-0.1~bzr33/src/http/response.h0000644000175000017500000000367212335423210017521 0ustar mathieumathieu#ifndef _HTTP_RESPONSE_H_ #define _HTTP_RESPONSE_H_ #include #include #include #include #include "protocol.h" namespace http { using namespace std; /** * Class used to identify a HTTP response. It is possible to * use this class with standard streams. * * @see Request */ class Response { private: /** * Class used for the initializer. */ class StatusCodesInitializer { public: StatusCodesInitializer(); }; /** * The initializer of the StatusCodes member. */ static StatusCodesInitializer statusCodesInitializer; public: int code; ///< Status code Protocol protocol; ///< Protocol version /** * Map with the strings associated to the most commonly * used status codes. In order to use a new user defined * status code, it is necessary to include in this map * the associated string. */ static map StatusCodes; /** * Initializes the response. * @param code Status code (200 by default). * @param protocol Protocol version (1.1 by default). */ Response(int code = 200, const Protocol& protocol = Protocol(1, 1)) { this->code = code; this->protocol = protocol; } friend ostream& operator << (ostream &out, const Response &response) { return out << response.protocol << " " << response.code << " " << Response::StatusCodes[response.code] << Protocol::CRLF; } friend istream& operator >> (istream &in, Response &response) { string line, cad; if(getline(in, line)) { if(line.size() <= 0) in.setstate(istream::failbit); else { istringstream in_str(line); if(!(in_str >> response.protocol >> response.code >> cad)) in.setstate(istream::failbit); } } return in; } }; } #endif /* _HTTP_RESPONSE_H_ */ esajpip-0.1~bzr33/src/http/protocol.h0000644000175000017500000000407212335423210017517 0ustar mathieumathieu#ifndef _HTTP_PROTOCOL_H_ #define _HTTP_PROTOCOL_H_ #include #include #include namespace http { using namespace std; /** * Class used to identify the HTTP protocol. It is possible * to use this class with standard streams. */ class Protocol { private: int mayorVersion_; ///< Mayor protocol version int minorVersion_; ///< Minor protocol version public: /** * String with the characters 13 (CR) and 10 (LF), * the line separator used in the HTTP protocol. */ static const char CRLF[]; /** * Initialized the protocl with the given version. By * default the version is 1.1. * @param mayorVersion Mayor protocol version * @param minorVersion Minor protocol version */ Protocol(int mayorVersion = 1, int minorVersion = 1) { assert(((mayorVersion == 1) && (minorVersion == 0)) || ((mayorVersion == 1) && (minorVersion == 1))); mayorVersion_ = mayorVersion; minorVersion_ = minorVersion; } /** * Copy constructor. */ Protocol(const Protocol& protocol) { mayorVersion_ = protocol.mayorVersion_; minorVersion_ = protocol.minorVersion_; } friend ostream& operator << (ostream &out, const Protocol &protocol) { return out << "HTTP/" << protocol.mayorVersion_ << "." << protocol.minorVersion_; } friend istream& operator >> (istream &in, Protocol &protocol) { string cad; in >> cad; if(!cad.compare(0, 8, "HTTP/1.0")) protocol = Protocol(1, 0); else if(!cad.compare(0, 8, "HTTP/1.1")) protocol = Protocol(1, 1); else in.setstate(istream::failbit); return in; } /** * Returns the mayor number of the protocol version. */ int mayorVersion() const { return mayorVersion_; } /** * Returns the minor number of the protocol version. */ int minorVersion() const { return minorVersion_; } }; } #endif /* _HTTP_PROTOCOL_H_ */ esajpip-0.1~bzr33/src/http/request.cc0000644000175000017500000000353012335423210017502 0ustar mathieumathieu//#define SHOW_TRACES #include "trace.h" #include "request.h" namespace http { void Request::ParseParameter(istream& stream, const string& param, string& value) { getline(stream, value, '&'); } void Request::ParseParameters(istream& stream) { string param, value; parameters.clear(); while(stream.good()) { value.clear(); getline(stream, param, '='); ParseParameter(stream, param, value); if(stream) parameters[param] = value; } } bool Request::Parse(const string &line) { string cad, uri; type = Request::UNKNOWN; if(line.size() > 0) { istringstream in(line); if(in >> cad >> uri >> protocol) { if(cad == "POST") type = Request::POST; else if(cad == "GET") type = Request::GET; if(type != Request::UNKNOWN) { ParseURI(uri); return true; } } } return false; } istream& operator >> (istream &in, Request &request) { string line; if(getline(in, line)) { TRACE("HTTP Request: " << line); if(!request.Parse(line)) in.setstate(istream::failbit); } return in; } ostream& operator << (ostream& out, const Request& request) { if(request.type != Request::UNKNOWN) { out << (request.type == Request::GET ? "GET" : "POST") << " " << request.object; if(request.parameters.size() > 0) { out << "?"; map::const_iterator i = request.parameters.begin(); if(!i->second.empty()) out << i->first << "=" << i->second; else out << i->first; while(++i != request.parameters.end()) { out << "&"; if(!i->second.empty()) out << i->first << "=" << i->second; else out << i->first; } } out << " " << request.protocol << Protocol::CRLF; } return out; } } esajpip-0.1~bzr33/src/http/http.h0000644000175000017500000000030312335423210016626 0ustar mathieumathieu#ifndef _HTTP_HTTP_H_ #define _HTTP_HTTP_H_ /** * Contains the definition of a set of classes for working * easily with the protocol HTTP. */ namespace http { } #endif /* _HTTP_HTTP_H_ */ esajpip-0.1~bzr33/src/http/request.h0000644000175000017500000000432312335423210017345 0ustar mathieumathieu#ifndef _HTTP_REQUEST_H_ #define _HTTP_REQUEST_H_ #include #include #include #include #include #include #include "header.h" #include "protocol.h" namespace http { using namespace std; /** * Class used to identify a HTTP request (GET or POST). It * is possible to use this class with standard streams. * * @see Response */ class Request { public: /** * Request type enumeration. */ enum Type { GET, POST, UNKNOWN }; Type type; ///< Request type (GET or POST) string object; ///< Object associated to the request Protocol protocol; ///< Protocol version used /** * Map with all the parameters when using the CGI form. */ map parameters; /** * Initializes the request. * @param type Request type (GET by default). * @param uri Request URI ("/" by default). * @param protocol Protocol version (1.1 by default). */ Request(Type type = Request::GET, const string& uri = "/", const Protocol& protocol = Protocol(1, 1)) { this->type = type; this->protocol = protocol; ParseURI(uri); } /** * Parses a request from a string. * @param line String that contains the request to parse. * @return true if successful. */ bool Parse(const string& line); /** * Parses a URI from a string. * @param uri String that contains the URI to parse. */ void ParseURI(const string& uri) { istringstream uri_str(uri); getline(uri_str, object, '?'); ParseParameters(uri_str); } /** * Parses the parameters from an input stream. * @param stream Input stream. */ virtual void ParseParameters(istream& stream); /** * Parses one parameter from an input stream. * @param stream Input stream. * @param param Parameter name. * @param value Parameter value. */ virtual void ParseParameter(istream& stream, const string& param, string& value); friend istream& operator >> (istream &in, Request &request); friend ostream& operator << (ostream& out, const Request& request); }; } #endif /* _REQUEST_H_ */ esajpip-0.1~bzr33/src/tr1_compat.h0000644000175000017500000000045512335423210016751 0ustar mathieumathieu#ifndef _TR1_COMPAT_H_ #define _TR1_COMPAT_H_ #ifndef _USE_BOOST #if (__cplusplus >= 201103L) || defined(_NO_TR1) #include #define SHARED_PTR std::shared_ptr #else #include #define SHARED_PTR std::tr1::shared_ptr #endif #else #include #endif #endif esajpip-0.1~bzr33/src/client_manager.cc0000644000175000017500000001622012335423210020003 0ustar mathieumathieu#include "trace.h" #include "client_manager.h" #include "jpip/jpip.h" #include "jpip/request.h" #include "jpip/databin_server.h" #include "http/header.h" #include "http/response.h" #include "net/socket_stream.h" #include "jpeg2000/index_manager.h" using namespace std; using namespace net; using namespace http; using namespace jpip; using namespace jpeg2000; void ClientManager::Run(ClientInfo *client_info) { SocketStream sock_stream(client_info->sock()); string channel = base::to_string(client_info->base_id()); int chunk_len = 0; int buf_len = cfg.max_chunk_size(); char *buf = new char[buf_len]; if(buf == NULL) { ERROR("Insufficient memory to manage a new client session"); return; } bool com_error; string req_line; jpip::Request req; bool pclose = false; bool is_opened = false; bool send_data = false; ImageIndex::Ptr im_index; DataBinServer data_server; string backup_file = cfg.caching_folder() + base::to_string(client_info->father_sock()) + ".backup"; if(File::Exists(backup_file.c_str())) { InputStream().Open(backup_file.c_str()).Serialize(req.cache_model); is_opened = true; } while(!pclose) { if(cfg.log_requests()) LOGC(_BLUE, "Waiting for a request ..."); if(cfg.com_time_out() > 0) { if(sock_stream->WaitForInput(cfg.com_time_out() * 1000) == 0) { LOG("Communication time-out"); sock_stream->Close(); break; } } com_error = true; if(getline(sock_stream, req_line).good()) com_error = !req.Parse(req_line); if(com_error) { if(sock_stream->IsValid()) LOG("Incorrect request received"); else LOG("Connection closed by the client"); sock_stream->Close(); break; } else { if(cfg.log_requests()) LOGC(_BLUE, "Request: " << req_line); http::Header header; int content_length = 0; while((sock_stream >> header).good()) { if(header == http::Header::ContentLength()) content_length = atoi(header.value.c_str()); } if(req.type == http::Request::POST) { stringstream body; sock_stream.clear(); while(content_length--) body.put((char)sock_stream.get()); req.ParseParameters(body); } sock_stream.clear(); } pclose = true; send_data = false; if (req.mask.items.cclose) { if(!is_opened) LOG("Close request received but there is not any channel opened"); else if(req.parameters["cclose"] != channel) LOG("Close request received related to another channel"); else { pclose = false; is_opened = false; req.cache_model.Clear(); unlink(backup_file.c_str()); index_manager.CloseImage(im_index); LOG("The channel " << channel << " has been closed"); sock_stream << http::Response(200) << http::Header::ContentLength("0") << http::Protocol::CRLF << flush; } } else if (req.mask.items.cnew) { if(is_opened) LOG("There already is a channel opened. Only one channel per client is supported"); else { string file_name = (req.mask.items.target ? req.parameters["target"] : req.object); if (!index_manager.OpenImage(file_name, &im_index)) ERROR("The image file '" << file_name << "' can not be read"); else if(!data_server.Reset(im_index)) ERROR("The image file '" << file_name << "' can not be opened"); else if(!data_server.SetRequest(req)) ERROR("The server can not process the request"); else { LOG("The channel " << channel << " has been opened for the image '" << file_name << "'"); sock_stream << http::Response(200) << http::Header("JPIP-cnew", "cid=" + channel + ",path=jpip,transport=http") << http::Header("JPIP-tid", index_manager.file_manager().GetCacheFileName(file_name)) << http::Header::CacheControl("no-cache") << http::Header::TransferEncoding("chunked") << http::Header::ContentType("image/jpp-stream") << http::Protocol::CRLF << flush; OutputStream().Open(backup_file.c_str()).Serialize(req.cache_model); is_opened = true; send_data = true; } } } else if (req.mask.items.cid) { if(!is_opened) LOG("Request received but no channel is opened"); else { if(req.parameters["cid"] != channel) LOG("Request related to another channel"); else if(!data_server.SetRequest(req)) ERROR("The server can not process the request"); else { sock_stream << http::Response(200) << http::Header::CacheControl("no-cache") << http::Header::TransferEncoding("chunked") << http::Header::ContentType("image/jpp-stream") << http::Protocol::CRLF << flush; send_data = true; } } } else { LOG("Invalid request (channel parameter not found)"); } pclose = pclose && !send_data; if(pclose) sock_stream << http::Response(500) << http::Protocol::CRLF << flush; else if(send_data) { for(bool last = false; !last;) { chunk_len = buf_len; if(!data_server.GenerateChunk(buf, &chunk_len, &last)) { ERROR("A new data chunk could not be generated"); pclose = true; break; } if(chunk_len > 0) { sock_stream << hex << chunk_len << dec << http::Protocol::CRLF << flush; //LOG("Chunk of " << chunk_len << " bytes sent"); sock_stream->Send(buf, chunk_len); sock_stream << http::Protocol::CRLF << flush; } } sock_stream << "0" << http::Protocol::CRLF << http::Protocol::CRLF << flush; if(data_server.end_woi()) OutputStream().Open(backup_file.c_str()).Serialize(req.cache_model); } } if(is_opened) { unlink(backup_file.c_str()); index_manager.CloseImage(im_index); } delete [] buf; } void ClientManager::RunBasic(ClientInfo *client_info) { jpip::Request req; int buff_len = 5000; char *buff = new char[buff_len]; SocketStream sock_stream(client_info->sock()); for (;;) { LOG("Waiting for a request ..."); if(cfg.com_time_out() > 0) { if(sock_stream->WaitForInput(cfg.com_time_out() * 1000) == 0) { LOG("Communication time-out"); sock_stream->Close(); break; } } if (!(sock_stream >> req).good()) { if(sock_stream->IsValid()) LOG("Incorrect request received"); else LOG("Connection closed by the client"); sock_stream->Close(); break; } else { http::Header header; while ((sock_stream >> header).good()); sock_stream.clear(); } sock_stream << http::Response(200) << http::Header("JPIP-cnew", "cid=C0,path=jpip,transport=http") << http::Header("JPIP-tid", "T0") << http::Header::CacheControl("no-cache") << http::Header::ContentLength(base::to_string(buff_len)) << http::Header::ContentType("image/jpp-stream") << http::Protocol::CRLF << flush; sock_stream->Send(buff, buff_len); } } esajpip-0.1~bzr33/src/jpip/0000755000175000017500000000000012335423210015465 5ustar mathieumathieuesajpip-0.1~bzr33/src/jpip/woi_composer.h0000644000175000017500000001233312335423210020345 0ustar mathieumathieu#ifndef _JPIP_WOI_COMPOSER_H_ #define _JPIP_WOI_COMPOSER_H_ #include "woi.h" #include "jpeg2000/packet.h" #include "jpeg2000/coding_parameters.h" namespace jpip { using namespace std; using namespace jpeg2000; /** * By means of this class it is possible to find out the * which packets of an image are associated to a WOI. * Given a WOI and the coding parameters of an image, the * code of this class allows to navigate, following the * LRCP order, through all the associated packets. * * @see WOI * @see CodingParameters */ class WOIComposer { private: Point pxy1; ///< Upper-left corner of the WOI Point pxy2; ///< Bottom-right corner of the WOI bool more_packets; ///< Flag to control the last packet int max_resolution; ///< Maximum resolution Size min_precinct_xy; ///< Minimum precinct Size max_precinct_xy; ///< Maximum precinct Packet current_packet; ///< Current packet /** * Pointer to the associated coding parameters. */ CodingParameters::Ptr coding_parameters; public: /** * Initializes the object. No packets are available. */ WOIComposer() { more_packets = false; } /** * Copy constructor. */ WOIComposer(const WOIComposer& composer) { *this = composer; } /** * Initializes the object. No packets are available. * @param coding_parameters Pointer to the coding parameters. */ WOIComposer(CodingParameters::Ptr coding_parameters) { more_packets = false; this->coding_parameters = coding_parameters; } /** * Resets the packets navigation and starts a new one. Sets the * current packet to the first packet of the WOI, assuming a * LRCP order. * @param woi New WOI to use. * @param coding_parameters Coding parameters to use. */ void Reset(const WOI& woi, CodingParameters::Ptr coding_parameters) { more_packets = true; current_packet = Packet(); max_resolution = woi.resolution; this->coding_parameters = coding_parameters; pxy1 = woi.position * (1L << (coding_parameters->num_levels - woi.resolution)); pxy2 = (woi.position + woi.size - 1) * (1L << (coding_parameters->num_levels - woi.resolution)); min_precinct_xy = coding_parameters->GetPrecincts(current_packet.resolution, pxy1); if (min_precinct_xy.x != 0) min_precinct_xy.x--; if (min_precinct_xy.y != 0) min_precinct_xy.y--; max_precinct_xy = coding_parameters->GetPrecincts(current_packet.resolution, pxy2); if (max_precinct_xy.x != 0) max_precinct_xy.x--; if (max_precinct_xy.y != 0) max_precinct_xy.y--; current_packet.precinct_xy = min_precinct_xy; } /** * Copy assignment. */ WOIComposer& operator=(const WOIComposer& composer) { pxy1 = composer.pxy1; pxy2 = composer.pxy2; more_packets = composer.more_packets; max_resolution = composer.max_resolution; current_packet = composer.current_packet; min_precinct_xy = composer.min_precinct_xy; max_precinct_xy = composer.max_precinct_xy; coding_parameters = composer.coding_parameters; return *this; } /** * Returns the current packet. */ Packet GetCurrentPacket() const { return current_packet; } /** * Moves to the next packet of the WOI. * @param packet Pointer to store the current packet (not the next one). * @return true if successful. */ bool GetNextPacket(Packet *packet = NULL) { if(!more_packets) return false; else { if(packet) *packet = current_packet; if (current_packet.precinct_xy.x < max_precinct_xy.x) current_packet.precinct_xy.x++; else { current_packet.precinct_xy.x = min_precinct_xy.x; if (current_packet.precinct_xy.y < max_precinct_xy.y) current_packet.precinct_xy.y++; else { current_packet.precinct_xy.y = min_precinct_xy.y; if (current_packet.component < (coding_parameters->num_components - 1)) current_packet.component++; else { current_packet.component = 0; if (current_packet.resolution < max_resolution) current_packet.resolution++; else { current_packet.resolution = 0; if (current_packet.layer < (coding_parameters->num_layers - 1)) current_packet.layer++; else { more_packets = false; return true; } } min_precinct_xy = coding_parameters->GetPrecincts(current_packet.resolution, pxy1); if (min_precinct_xy.x != 0) min_precinct_xy.x--; if (min_precinct_xy.y != 0) min_precinct_xy.y--; max_precinct_xy = coding_parameters->GetPrecincts(current_packet.resolution, pxy2); if (max_precinct_xy.x != 0) max_precinct_xy.x--; if (max_precinct_xy.y != 0) max_precinct_xy.y--; current_packet.precinct_xy = min_precinct_xy; } } } return true; } } virtual ~WOIComposer() { } }; } #endif /* _JPIP_INDEX_MANAGER_H_ */ esajpip-0.1~bzr33/src/jpip/databin_server.h0000644000175000017500000001503612335423210020633 0ustar mathieumathieu#ifndef _JPIP_DATABIN_SERVER_H_ #define _JPIP_DATABIN_SERVER_H_ //#define SHOW_TRACES #include #include "trace.h" #include "data/file.h" #include "jpip/woi.h" #include "jpip/request.h" #include "jpip/cache_model.h" #include "jpip/woi_composer.h" #include "jpip/databin_writer.h" #include "jpeg2000/range.h" #include "jpeg2000/image_index.h" namespace jpip { using namespace std; using namespace data; using namespace jpeg2000; /** * Contains the core functionality of a (JPIP) data-bin server, * which maintains a cache model and is capable of generating * data chunks of variable length; */ class DataBinServer { private: WOI woi; ///< Current WOI int pending; ///< Number of pending bytes Range range; ///< Range of codestreams bool has_woi; ///< true if the last request contained a WOI bool metareq; ///< true if the last request contained a "metareq" bool end_woi_; ///< true if the WOI has been completely sent File::Ptr file; ///< Pointer to the associated image file int current_idx; ///< Current codestream index /** * true if the end has been reached and the last write operation * could not be completed. */ bool eof; CacheModel cache_model; ///< Cache model of the client vector files; ///< List of files (for hyperlinked JPX files) WOIComposer woi_composer; ///< WOI composer for determining the packets ImageIndex::Ptr im_index; ///< Pointer to the associated image index DataBinWriter data_writer; ///< Data-bin writer for generating the chunks enum { MINIMUM_SPACE = 60 ///< Minimum space in the chunk }; /** * Writes a new data-bin segment or a part of it that is not already cached. * @param num_codestream Index number of the codestream. * @param id Data-bin identifier. * @param segment File segment associated. * @param offset Data-bin offset of the data (0 by default). * @param last true if this is the last data of the data-bin. * @return 1 if the segment content was completely written and/or cached, * 0 if it was incompletely written (or not at all, if EOF flag is set), * or -1 if an error was generated. */ template int WriteSegment(int num_codestream, int id, FileSegment segment, int offset = 0, bool last = true) { int cached = cache_model.GetDataBin(num_codestream, id); int res = 1, seg_cached = cached - offset; if((cached != INT_MAX) && (((int)segment.length - seg_cached) >= 0)) { int free = data_writer.GetFree() - MINIMUM_SPACE; if(free <= 0) { eof = true; res = 0; } else { segment.RemoveFirst(seg_cached); if((int)segment.length > free) { segment.length = free; last = false; res = 0; } data_writer.SetCodestream(num_codestream); data_writer.SetDataBinClass(BIN_CLASS); File::Ptr file_ptr; if(BIN_CLASS == DataBinClass::META_DATA) file_ptr = file; else { int idx = range.GetIndex(num_codestream); if((int)files.size() <= idx) return -1; file_ptr = files[idx]; } if(!data_writer.Write(id, cached, *file_ptr, segment, last)) res = -1; else cache_model.AddToDataBin(num_codestream, id, segment.length, last); } } return res; } /** * Writes a new place-holder segment, only if it is possible to write it completely. * @param num_codestream Index number of the codestream. * @param id Data-bin identifier. * @param place_holder Place-holder information. * @param offset Data-bin offset of the data (0 by default). * @param last true if this is the last data of the data-bin. * @return 1 if the segment content was completely written and/or cached, * 0 if it was incompletely written (or not at all, if EOF flag is set), * or -1 if an error was generated. */ int WritePlaceHolder(int num_codestream, int id, const PlaceHolder& place_holder, int offset = 0, bool last = false) { int cached = cache_model.GetDataBin(num_codestream, id); int res = 1, seg_cached = cached - offset; if((cached != INT_MAX) && (((int)place_holder.length() - seg_cached) > 0)) { int free = data_writer.GetFree() - MINIMUM_SPACE - place_holder.length(); if(free <= 0) { eof = true; res = 0; } else { data_writer.SetCodestream(num_codestream); data_writer.SetDataBinClass(DataBinClass::META_DATA); if(!data_writer.WritePlaceHolder(id, cached, *file, place_holder, last)) res = -1; else cache_model.AddToDataBin(num_codestream, id, place_holder.length(), last); } } return res; } public: /** * Initializes the obect. */ DataBinServer() { pending = 0; has_woi = false; end_woi_ = false; metareq = false; current_idx = 0; } /** * Returns true if the end of the WOI has been reached, * that is, there is not more associated packets to send. */ bool end_woi() const { return end_woi_; } /** * Resets the server assigning a new image to serve. It * also resets the maintained cache model. * @param image_index Pointer to the new image index to use. * @return true if successful. */ bool Reset(const ImageIndex::Ptr image_index); /** * Sets the new current request to take into account for * generating the chunks of data. * @param req Request. * @return true if successful. */ bool SetRequest(const Request& req); /** * Generates a new chunk of data for the current image and * WOI, according to the last indicated request. * @param buff Pointer to the memory buffer. * @param len Length of the memory buffer. It is modified * by the method to indicate how many bytes have been * written to the buffer. * @param last Output parameter to indicates if this is * the last chunk of data associated to the last request. * @return true if successful. */ bool GenerateChunk(char *buff, int *len, bool *last); virtual ~DataBinServer() { } }; } #endif /* _JPIP_DATABIN_SERVER_H_ */ esajpip-0.1~bzr33/src/jpip/woi.h0000644000175000017500000000422312335423210016435 0ustar mathieumathieu#ifndef _JPIP_WOI_H_ #define _JPIP_WOI_H_ #include #include "jpeg2000/point.h" namespace jpip { using namespace std; using namespace jpeg2000; /** * Class that identifies a WOI (Window Of Interest). This term * refers, from the point of view of the JPIP protocol, to a * rectangular region of an image, for a resolution level. This * class can be printed. * * @see Point */ class WOI { public: Size size; ///< Size of the WOI (width and height) Point position; ///< Position of the upper-left corner of the WOI int resolution; ///< Resolution level where the WOI is located (0 == the highest) /** * Initializes the resolution level to zero. */ WOI() { resolution = 0; } /** * Initializes the object. * @param position Position of the WOI. * @param size Size of the WOI. * @param resolution Resolution level of the WOI. */ WOI(const Point& position, const Size& size, int resolution) { this->size = size; this->position = position; this->resolution = resolution; } /** * Copy constructor. */ WOI(const WOI& woi) { *this = woi; } /** * Copy assignment. */ WOI& operator=(const WOI& woi) { this->size = woi.size; this->position = woi.position; this->resolution = woi.resolution; return *this; } /** * Returns true if the two given WOIs * are equal. */ friend bool operator==(const WOI& a, const WOI& b) { return ((a.position == b.position) && (a.size == b.size) && (a.resolution == b.resolution)); } /** * Returns true if the two given WOIs * are not equal. */ friend bool operator!=(const WOI& a, const WOI& b) { return !(a == b); } friend ostream& operator << (ostream &out, const WOI &woi) { out << "(" << woi.position.x << ", " << woi.position.y << ", " << woi.size.x << ", " << woi.size.y << ", " << woi.resolution << ")"; return out; } virtual ~WOI() { } }; } #endif /* _JPIP_WOI_H_ */ esajpip-0.1~bzr33/src/jpip/databin_writer.h0000644000175000017500000001304012335423210020632 0ustar mathieumathieu#ifndef _JPIP_DATABIN_WRITER_H_ #define _JPIP_DATABIN_WRITER_H_ #include #include "jpip.h" #include "data/file.h" #include "data/file_segment.h" #include "jpeg2000/place_holder.h" namespace jpip { using namespace std; using namespace data; using namespace jpeg2000; /** * Class used to generate data-bin segments and write them * into a memory buffer. * * @see DataBinServer * @see DataBinClass * @see EOR */ class DataBinWriter { private: /** * true if the end of the buffer has been reached and * the last value could not be written. */ bool eof; char *ini; ///< Pointer to the beginning of the buffer char *ptr; ///< Current position of the buffer char *end; ///< Pointer to the end of the buffer int databin_class; ///< Current data-bin class int codestream_idx; ///< Current codestream index number int prev_databin_class; ///< Previous data-bin class int prev_codestream_idx; ///< Previous codestream index number /** * Writes a value into the buffer. * @param value Value to write. * @return The object itself. */ template DataBinWriter& WriteValue(T value) { if(!eof) { if((ptr + sizeof(T)) >= end) eof = true; else { for (int i = sizeof(T) - 1; i >= 0; i--) *ptr++ = (value >> (8 * i)) & 0xFF; } } return *this; } /** * Writes a new integer value into the buffer coded as VBAS. * @param value Value to write. * @return The object itself. */ DataBinWriter& WriteVBAS(uint64_t value); /** * Writes a data-bin header into the buffer. * @param bin_id Data-bin identifier. * @param bin_offset Data-bin offset. * @param bin_length Data-bin length. * @param last_byte true if the data related * to this header contains the last byte of the data-bin. * @return The object itself. */ DataBinWriter& WriteHeader(uint64_t bin_id, uint64_t bin_offset, uint64_t bin_length, bool last_byte = false); public: /** * Initializes the object. */ DataBinWriter() { eof = true; databin_class = -1; codestream_idx = -1; prev_databin_class = -1; prev_codestream_idx = -1; ini = ptr = end = NULL; } /** * Sets the associated memory buffer. * @param buf Memory buffer. * @param buf_len Length of the memory buffer. * @return The object itself. */ DataBinWriter& SetBuffer(char *buf, int buf_len) { eof = false; ini = ptr = buf; end = ini + buf_len; return *this; } /** * Clears the previous identifiers of data-bin * class and codestream index numbers. * @return The object itself. */ DataBinWriter& ClearPreviousIds() { databin_class = -1; codestream_idx = -1; prev_databin_class = -1; prev_codestream_idx = -1; return *this; } /** * Sets the current codestream. * @param value Index number of the codestream. * @return The object itself. */ DataBinWriter& SetCodestream(int value) { if(value < 0) value = 0; codestream_idx = value; return *this; } /** * Sets the current data-bin class. * @param databin_class Data-bin class. * @return The object itself. */ DataBinWriter& SetDataBinClass(int databin_class) { this->databin_class = databin_class; return *this; } /** * Writes a data-bin segment into the buffer. * @param bin_id Data-bin identifier. * @param bin_offset Data-bin offset. * @param file File from where to read the data. * @param segment File segment of the data. * @param last_byte true if the data * contains the last byte of the data-bin. * @return The object itself. */ DataBinWriter& Write(uint64_t bin_id, uint64_t bin_offset, const File& file, const FileSegment& segment, bool last_byte = false); /** * Writes a place-holder segment into the buffer. * @param bin_id Data-bin identifier. * @param bin_offset Data-bin offset. * @param file File from where to read the data. * @param place_holder Place-holder information. * @param last_byte true if the data * contains the last byte of the data-bin. * @return The object itself. */ DataBinWriter& WritePlaceHolder(uint64_t bin_id, uint64_t bin_offset, const File& file, const PlaceHolder& place_holder, bool last_byte = false); /** * Writes an empty segment. * @param bin_id Data-bin identifier. * @return The object itself. */ DataBinWriter& WriteEmpty(uint64_t bin_id = 0); /** * Returns the number of bytes written. */ int GetCount() const { return (ptr - ini); } /** * Returns the number of bytes available. */ int GetFree() const { return (end - ptr); } /** * Writes a EOR message into the buffer. * @param reason Reason of the message. * @return The object itself. */ DataBinWriter& WriteEOR(int reason) { if((ptr + 3) > end) eof = true; else { *ptr++ = 0; *ptr++ = (char)reason; *ptr++ = 0; } return *this; } /** * Returns the EOF status of the * object. */ operator bool() const { return !eof; } virtual ~DataBinWriter() { } }; } #endif /* _JPIP_DATABIN_WRITER_H_ */ esajpip-0.1~bzr33/src/jpip/databin_writer.cc0000644000175000017500000000701612335423210020776 0ustar mathieumathieu#include "databin_writer.h" namespace jpip { DataBinWriter& DataBinWriter::WriteVBAS(uint64_t value) { if(!eof) { if(ptr >= end) eof = true; else { int num = 0; uint8_t bytes[10]; do { bytes[num++] = (uint8_t)(value & 0x0000007F); value >>= 7; } while(value); if((ptr + num) > end) eof = true; else { while(num-- > 1) *ptr++ = bytes[num] | 0x80; *ptr++ = bytes[num]; } } } return *this; } DataBinWriter& DataBinWriter::WriteHeader(uint64_t bin_id, uint64_t bin_offset, uint64_t bin_length, bool last_byte) { if(!eof) { if(ptr >= end) eof = true; else { char *aux_ptr = ptr; int pres = 1; if(prev_databin_class != databin_class) pres = 2; if(prev_codestream_idx != codestream_idx) pres = 3; uint8_t first_b = (uint8_t)(pres << 5); if(last_byte) first_b |= (uint8_t)(1 << 4); if(!(bin_id >> 4)) { first_b |= (uint8_t)(bin_id & 0x0F); *ptr++ = first_b; } else { *ptr++ = (first_b | (uint8_t)0x80); WriteVBAS(bin_id); } if(pres >= 2) { WriteVBAS((uint64_t)databin_class); if(pres == 3) WriteVBAS((uint64_t)codestream_idx); } WriteVBAS(bin_offset); WriteVBAS(bin_length); if(eof) ptr = aux_ptr; } } return *this; } DataBinWriter& DataBinWriter::Write(uint64_t bin_id, uint64_t bin_offset, const File& file, const FileSegment& segment, bool last_byte) { char *aux_ptr = ptr; if(WriteHeader(bin_id, bin_offset, segment.length, last_byte)) { if(segment.length > 0) { file.Seek(segment.offset); if((ptr + segment.length) >= end) eof = true; else if(!file.Read(ptr, segment.length)) eof = true; else ptr += segment.length; } if(eof) ptr = aux_ptr; else { prev_databin_class = databin_class; prev_codestream_idx = codestream_idx; } } return *this; } DataBinWriter& DataBinWriter::WritePlaceHolder(uint64_t bin_id, uint64_t bin_offset, const File& file, const PlaceHolder& place_holder, bool last_byte) { char *aux_ptr = ptr; if(WriteHeader(bin_id, bin_offset, place_holder.length(), last_byte)) { if((ptr + place_holder.length()) >= end) eof = true; else { /* LBox */ WriteValue(place_holder.length()); /* TBox */ WriteValue(0x70686c64); /* Flags */ WriteValue(place_holder.is_jp2c ? 4 : 1); /* OrigID */ WriteValue(place_holder.is_jp2c ? 0 : place_holder.id); /* OrigBH */ if(place_holder.header.length > 0) { file.Seek(place_holder.header.offset); if((ptr + place_holder.header.length) >= end) eof = true; else if(!file.Read(ptr, place_holder.header.length)) eof = true; else ptr += place_holder.header.length; } /* EquivID */ WriteValue(0); /* EquivBH */ WriteValue(0); /* CSID */ WriteValue(place_holder.is_jp2c ? place_holder.id : 0); if(eof) ptr = aux_ptr; else { prev_databin_class = databin_class; prev_codestream_idx = codestream_idx; } } } return *this; } DataBinWriter& DataBinWriter::WriteEmpty(uint64_t bin_id) { File aux_file; return this->Write(bin_id, 0, aux_file, FileSegment::Null, true); } } esajpip-0.1~bzr33/src/jpip/jpip.h0000644000175000017500000000634512335423210016610 0ustar mathieumathieu#ifndef _JPIP_JPIP_H_ #define _JPIP_JPIP_H_ /** * Set of classes related to the JPIP protocol, defined in * the Part 9 of the JPEG2000 standard. */ namespace jpip { /** * Class that contains the definitions of all the * data-bin classes defined for the JPIP protocol. * It is not possible to create an object of this * class. */ class DataBinClass { private: DataBinClass() {} public: enum { /** * Class identifier for precinct data-bins. */ PRECINCT = 0, /** * Class identifier for extended precinct data-bins. */ EXTENDED_PRECINCT = 1, /** * Class identifier for tile header data-bins. */ TILE_HEADER = 2, /** * Class identifier for tile data-bins. */ TILE_DATA = 4, /** * Class identifier for extended tile data-bins. */ EXTENDED_TILE = 5, /** * Class identifier for main header data-bins. */ MAIN_HEADER = 6, /** * Class identifier for meta-data data-bins. */ META_DATA = 8 }; /** * Returns a string with the name of the databin class name given, */ static const char *GetName(int class_name); }; /** * Class that contains all the definitions of the EOF * messages defined for the JPIP protocol. It is not * possible to create an object of this class. */ class EOR { private: EOR() {} public: enum { /** * EOR code sent when the server has transferred all available image * information (not just information relevant to the requested view-window) * to the client. */ IMAGE_DONE = 1, /** * EOR code sent when the server has transferred all available information * that is relevant to the requested view-window. */ WINDOW_DONE = 2, /** * EOR code sent when the server is terminating its response in order to * service a new request. */ WINDOW_CHANGE = 3, /** * EOR code sent when the server is terminating its response because the * byte limit specified in a byte limit specified in a max length request * field has been reached. */ BYTE_LIMIT_REACHED = 4, /** * EOR code sent when the server is terminating its response because the * quality limit specified in a quality request field has been reached. */ QUALITY_LIMIT_REACHED = 5, /** * EOR code sent when the server is terminating its response because some * limit on the session resources, e.g. a time limit, has been reached. No * further request should be issued using a channel ID assigned in that * session. */ SESSION_LIMIT_REACHED = 6, /** * EOR code sent when the server is terminating its response because some * limit, e.g., a time limit, has been reached. If the request is issued in * a session, further requests can still be issued using a channel ID * assigned in that session. */ RESPONSE_LIMIT_REACHED = 7, /** * EOR code sent when there is not any specific EOR reason. */ NON_SPECIFIED = 0xFF }; }; } #endif /* _JPIP_JPIP_H_ */ esajpip-0.1~bzr33/src/jpip/cache_model.cc0000644000175000017500000000003112335423210020211 0ustar mathieumathieu#include "cache_model.h" esajpip-0.1~bzr33/src/jpip/cache_model.h0000644000175000017500000002722512335423210020071 0ustar mathieumathieu#ifndef _JPIP_CACHE_MODEL_H_ #define _JPIP_CACHE_MODEL_H_ #include #include #include #include "base.h" #include "jpip/jpip.h" #include "data/serialize.h" namespace jpip { using namespace std; using namespace data; /** * Template class that is specialized for allowing basic operations * (add and get) with cache models depending on the data-bin classes. */ template struct DataBinSelector { }; /** * The cache model of a JPIP client is handled using this class. * It allows to maintain a cache model recording the amount of * data sent by the server regarding the meta-datas, headers, * tile-headers and precincts. This implementation only allows to * record incremental amounts, from the beginning of each entity. * The value INT_MAX is used to specify that an * item is complete. This class is serializable. */ class CacheModel { public: /** * Sub-class of the cache model class used to identify a * codestream. This class is serializable. */ class Codestream { private: int header; ///< Amount for the header int tile_header; ///< Amount for the tile-header vector precincts; ///< Amount for the precincts /** * Minimum identifier of the non-consecutive precinct * completely sent. All the initial precincts already * sent completely to the client are removed, so this * value contains the next precinct. The vector * precincts is related to the precincts * starting from this index. */ int min_precinct; public: /** * Initializes all the members to zero. */ Codestream() { header = 0; tile_header = 0; min_precinct = 0; } /** * Copy constructor. */ Codestream(const Codestream& model) { *this = model; } /** * Copy assignment. */ Codestream& operator=(const Codestream& model) { header = model.header; tile_header = model.tile_header; min_precinct = model.min_precinct; base::copy(precincts, model.precincts); return *this; } /** * Add the content of the given codestream cache model. */ Codestream& operator+=(const Codestream& model) { AddToMainHeader(model.header); AddToTileHeader(model.tile_header); for(int i = 0; i < (int)model.precincts.size(); i++) AddToPrecinct(model.min_precinct + i, model.precincts[i]); return *this; } template T& SerializeWith(T& stream) { return (stream & header & tile_header & min_precinct & precincts); } /** * Returns the amount of the main header. */ int GetMainHeader() const { return header; } /** * Returns the amount of the tile header. */ int GetTileHeader() const { return tile_header; } /** * Increases the amount of the main header. * @param amount Amount increment. * @param complete true if the main header * is complete after the increment. * @return the new amount value. */ int AddToMainHeader(int amount, bool complete = false) { if (header != INT_MAX) { if (complete || (amount == INT_MAX)) header = INT_MAX; else header += amount; } return header; } /** * Increases the amount of the tile header. * @param amount Amount increment. * @param complete true if the tile header * is complete after the increment. * @return the new amount value. */ int AddToTileHeader(int amount, bool complete = false) { if (tile_header != INT_MAX) { if (complete || (amount == INT_MAX)) tile_header = INT_MAX; else tile_header += amount; } return tile_header; } /** * Returns the amount of a precinct. * @param num_precinct Index number of the precinct. */ int GetPrecinct(int num_precinct) { if (num_precinct < min_precinct) return INT_MAX; else { int n = num_precinct - min_precinct; if (n >= (int) precincts.size()) precincts.resize(n + 1, 0); return precincts[n]; } } /** * Increases the amount of a precinct. * @param num_precinct Index number of the precinct. * @param amount Amount increment. * @param complete true if the precinct * is complete after the increment. * @return the new amount value. */ int AddToPrecinct(int num_precinct, int amount, bool complete = false) { if (num_precinct < min_precinct) return INT_MAX; else { int n = num_precinct - min_precinct; if (n >= (int) precincts.size()) precincts.resize(n + 1, 0); int& p = precincts[n]; if (p != INT_MAX) { if (complete || (amount == INT_MAX)) p = INT_MAX; else p += amount; } return p; } } /** * Packs the information stored regarding the precincts, * removing those initial elements that are consecutive * and completes. * @param min_sum Only the packing is performed if there * are a number of items equal or greater than this value * (1 by default). */ void Pack(int min_sum = 1) { int sum = 0; for (int i = 0; i < (int) precincts.size(); i++) { if (precincts[i] == INT_MAX) sum++; else break; } if (sum >= min_sum) { precincts.erase(precincts.begin(), precincts.begin() + sum); min_precinct += sum; } } }; private: /** * Says if the meta-data has been totally sent. */ bool full_meta; /** * Amounts for the meta-datas. */ vector meta_data; /** * Amounts for the codestreams. */ vector codestreams; public: /** * Empty constructor. */ CacheModel() { full_meta = false; } /** * Copy constructor. */ CacheModel(const CacheModel& model) { *this = model; } /** * Copy assignment. */ CacheModel& operator=(const CacheModel& model) { full_meta = model.full_meta; base::copy(meta_data, model.meta_data); base::copy(codestreams, model.codestreams); return *this; } /** * Add the content of the given cache model. */ CacheModel& operator+=(const CacheModel& model) { if(!full_meta) { for(int i = 0; i < (int)model.meta_data.size(); i++) AddToMetadata(i, model.meta_data[i]); } for(int i = 0; i < (int)model.codestreams.size(); i++) GetCodestream(i) += model.codestreams[i]; return *this; } template T& SerializeWith(T& stream) { return (stream & full_meta & meta_data & codestreams); } /** * Returns the reference of a codestream. * @param num_codestream Index number of the codestream. */ Codestream& GetCodestream(int num_codestream) { if (num_codestream >= (int) codestreams.size()) codestreams.resize(num_codestream + 1); return codestreams[num_codestream]; } /** * Returns the amount of a meta-data. * @param id Index number of the meta-data. */ int GetMetadata(int id) { if(full_meta) return INT_MAX; else { if(id >= (int)meta_data.size()) meta_data.resize(id + 1, 0); return meta_data[id]; } } /** * Increases the amount of a meta-data. * @param id Index number of the meta-data. * @param amount Amount increment. * @param complete true if the meta-data * is complete after the increment. * @return the new amount value. */ int AddToMetadata(int id, int amount, bool complete = false) { if(full_meta) return INT_MAX; else { if (GetMetadata(id) != INT_MAX) { if (complete || (amount == INT_MAX)) meta_data[id] = INT_MAX; else meta_data[id] += amount; } return meta_data[id]; } } /** * Returns the amount of a data-bin item using the class * DataBinSelector. * @param num_codestream Index number of the associated codestream. * @param id Index number of the data-bin. */ template int GetDataBin(int num_codestream, int id) { return DataBinSelector::Get(*this, num_codestream, id); } /** * Increases the amount of a data-bin item using the * class DataBinSelector. * @param num_codestream Index number of the associated codestream. * @param id Index number of the data-bin. * @param amount Amount increment. * @param complete true if the data-bin is complete * after the increment. * @return the new amount value. */ template int AddToDataBin(int num_codestream, int id, int amount, bool complete = false) { return DataBinSelector::AddTo(*this, num_codestream, id, amount, complete); } /** * Returns the full flag of the meta-datas. */ bool IsFullMetadata() const { return full_meta; } /** * Sets the full flag for the meta-datas to true. */ void SetFullMetadata() { full_meta = true; meta_data.clear(); } /** * Calls the Pack method of all the codestreams. */ void Pack(int min_sum = 1) { for (vector::iterator i = codestreams.begin(); i != codestreams.end(); i++) i->Pack(min_sum); } /** * Clear all the amounts. */ void Clear() { full_meta = false; meta_data.clear(); codestreams.clear(); } virtual ~CacheModel() { } }; template<> struct DataBinSelector { static int Get(CacheModel& model, int num_codestream, int id) { return model.GetMetadata(id); } static int AddTo(CacheModel& model, int num_codestream, int id, int amount, bool complete) { return model.AddToMetadata(id, amount, complete); } }; template<> struct DataBinSelector { static int Get(CacheModel& model, int num_codestream, int id) { return model.GetCodestream(num_codestream).GetMainHeader(); } static int AddTo(CacheModel& model, int num_codestream, int id, int amount, bool complete) { return model.GetCodestream(num_codestream).AddToMainHeader(amount, complete); } }; template<> struct DataBinSelector { static int Get(CacheModel& model, int num_codestream, int id) { return model.GetCodestream(num_codestream).GetTileHeader(); } static int AddTo(CacheModel& model, int num_codestream, int id, int amount, bool complete) { return model.GetCodestream(num_codestream).AddToTileHeader(amount, complete); } }; template<> struct DataBinSelector { static int Get(CacheModel& model, int num_codestream, int id) { return model.GetCodestream(num_codestream).GetPrecinct(id); } static int AddTo(CacheModel& model, int num_codestream, int id, int amount, bool complete) { return model.GetCodestream(num_codestream).AddToPrecinct(id, amount, complete); } }; } #endif /* _JPIP_CACHE_MODEL_H_ */ esajpip-0.1~bzr33/src/jpip/databin_server.cc0000644000175000017500000001200712335423210020764 0ustar mathieumathieu#include "databin_server.h" #include "data/file_segment.h" namespace jpip { bool DataBinServer::Reset(const ImageIndex::Ptr image_index) { files.clear(); metareq = false; has_woi = false; im_index = image_index; file = File::Ptr(new File()); if(!file->OpenForReading(im_index->GetPathName())) return false; else { if (!im_index->IsHyperLinked(0)) files.push_back(file); else { File::Ptr hyperlinked_file = File::Ptr(new File()); if (!hyperlinked_file->OpenForReading(im_index->GetPathName(0))) return false; else files.push_back(hyperlinked_file); } return true; } } bool DataBinServer::SetRequest(const Request& req) { bool res = true; bool reset_woi = false; data_writer.ClearPreviousIds(); if((has_woi = req.mask.HasWOI())) { WOI new_woi; new_woi.size = req.woi_size; new_woi.position = req.woi_position; req.GetResolution(*im_index, &new_woi); if(new_woi != woi) { reset_woi = true; woi = new_woi; } } if(req.mask.items.model) cache_model += req.cache_model; if (req.mask.items.metareq) metareq = true; if(req.mask.items.stream || req.mask.items.context) { Range new_range = Range(req.min_codestream, req.max_codestream); if(new_range != range) { reset_woi = true; if(new_range.Length() != range.Length()) files.resize(new_range.Length()); range = new_range; current_idx = range.first; for(int i = 0; i < range.Length(); i++) { int idx = range.GetItem(i); if(!im_index->IsHyperLinked(idx)) files[i] = file; else { files[i] = File::Ptr(new File()); res = res && files[i]->OpenForReading(im_index->GetPathName(idx)); } } } } if(req.mask.items.len) pending = req.length_response; if(reset_woi) { end_woi_ = false; woi_composer.Reset(woi, *im_index); } return res; } bool DataBinServer::GenerateChunk(char *buff, int *len, bool *last) { int res; data_writer.SetBuffer(buff, min(pending, *len)); if(pending > 0) { eof = false; if(!im_index->ReadLock(range)) { ERROR("The lock of the image '" << im_index->GetPathName() << "' can not be taken for reading"); return false; } if(!cache_model.IsFullMetadata()) { if(im_index->GetNumMetadatas() <= 0) WriteSegment(0, 0, FileSegment::Null); else { int bin_offset = 0; bool last_metadata = false; for (int i = 0; i < im_index->GetNumMetadatas(); i++) { last_metadata = (i == (im_index->GetNumMetadatas() - 1)); res = WriteSegment(0, 0, im_index->GetMetadata(i), bin_offset, last_metadata); bin_offset += im_index->GetMetadata(i).length; if (last_metadata) { if(res > 0) cache_model.SetFullMetadata(); } else { if (WritePlaceHolder(0, 0, im_index->GetPlaceHolder(i), bin_offset) <= 0) break; bin_offset += im_index->GetPlaceHolder(i).length(); } } } } if (!eof) { for (int i = range.first; i <= range.last; i++) { WriteSegment(i, 0, im_index->GetMainHeader(i)); WriteSegment(i, 0, FileSegment::Null); } if(has_woi) { Packet packet; FileSegment segment; int bin_id, bin_offset; bool last_packet = false; while(data_writer && !eof) { packet = woi_composer.GetCurrentPacket(); segment = im_index->GetPacket(current_idx, packet, &bin_offset); bin_id = im_index->GetCodingParameters()->GetPrecinctDataBinId(packet); last_packet = (packet.layer >= (im_index->GetCodingParameters()->num_layers - 1)); res = WriteSegment(current_idx, bin_id, segment, bin_offset, last_packet); if(res < 0) return false; else if(res > 0) { if (current_idx != range.last) current_idx++; else { if(!woi_composer.GetNextPacket()) break; else current_idx = range.first; } } } } } if(!eof) { data_writer.WriteEOR(EOR::WINDOW_DONE); end_woi_ = true; pending = 0; } else { pending -= data_writer.GetCount(); if(pending <= MINIMUM_SPACE + 100) { data_writer.WriteEOR(EOR::BYTE_LIMIT_REACHED); pending = 0; } } if(!im_index->ReadUnlock(range)) { ERROR("The lock of the image '" << im_index->GetPathName() << "' can not be released"); return false; } } *len = data_writer.GetCount(); *last = (pending <= 0); if(*last) cache_model.Pack(); return true; } } esajpip-0.1~bzr33/src/jpip/jpip.cc0000644000175000017500000000071312335423210016737 0ustar mathieumathieu#include "jpip.h" namespace jpip { const char *DataBinClass::GetName(int class_name) { static const char *names[] = { "PRECINCT", "EXTENDED_PRECINCT", "TILE_HEADER", "UNKNOWN", "TILE_DATA", "EXTENDED_TILE", "MAIN_HEADER", "UNKNOWN", "META_DATA" }; if((class_name < 0) || (class_name >= (int)sizeof(names))) return "UNKNOWN"; else return names[class_name]; } } esajpip-0.1~bzr33/src/jpip/woi_composer.cc0000644000175000017500000000000212335423210020471 0ustar mathieumathieu esajpip-0.1~bzr33/src/jpip/request.cc0000644000175000017500000001310612335423210017465 0ustar mathieumathieu#include "trace.h" #include "request.h" namespace jpip { void Request::ParseParameters(istream& stream) { mask.Clear(); http::Request::ParseParameters(stream); } void Request::ParseParameter(istream& stream, const string& param, string& value) { char c; int x, y; string aux; if (param == "target") mask.items.target = 1; else if (param == "cid") mask.items.cid = 1; else if (param == "cnew") mask.items.cnew = 1; else if (param == "cclose") mask.items.cclose = 1; else if (param == "metareq") mask.items.metareq = 1; else if (param == "fsiz") { if((stream >> x >> c >> y) && (c == ',')) { resolution_size.x = x; resolution_size.y = y; mask.items.fsiz = 1; if(stream.peek() == ',') { getline(stream.ignore(1), aux, '&'); if(!stream.eof()) stream.unget(); if (aux == "round-up") round_direction = ROUNDUP; else if (aux == "round-down") round_direction = ROUNDDOWN; else round_direction = CLOSEST; } TRACE("JPIP parameter: fsiz=" << resolution_size.x << "," << resolution_size.y << "," << aux); } } else if (param == "roff") { if((stream >> x >> c >> y) && (c == ',')) { woi_position.x = x; woi_position.y = y; mask.items.roff = 1; TRACE("JPIP parameter: roff=" << woi_position.x << "," << woi_position.y); } } else if (param == "rsiz") { if((stream >> x >> c >> y) && (c == ',')) { woi_size.x = x; woi_size.y = y; mask.items.rsiz = 1; TRACE("JPIP parameter: rsiz=" << woi_size.x << "," << woi_size.y); } } else if (param == "len") { if(stream >> x) { length_response = x; mask.items.len = 1; TRACE("JPIP parameter: len=" << length_response); } } else if (param == "stream") { if(stream >> x) { y = x; if(stream.peek() == ':') stream.ignore(1) >> y; if(stream) { min_codestream = x; max_codestream = y; mask.items.stream = 1; } TRACE("JPIP parameter: stream=" << min_codestream << ":" << max_codestream); } } else if (param == "model") { if(ParseModel(stream)) mask.items.model = 1; } else if (param == "context") { char jpxl_param[4]; stream.get(jpxl_param, 5); if (!strcmp(jpxl_param, "jpxl")) { char c; GetCodedChar(stream, c); if (c == '<') { if(stream >> x) { y = x; if(stream.peek() == '-') stream.ignore(1) >> y; GetCodedChar(stream, c); if(c=='>') { min_codestream = x; max_codestream = y; mask.items.context = 1; } } } TRACE("JPIP parameter: context=" << min_codestream << ":" << max_codestream); } } getline(stream, value, '&'); if(value.size() > 0) TRACE("JPIP parameter: " << param << "=" << value); } istream& Request::GetCodedChar(istream& in, char& c) { if(in.get(c)) { if(c == '%') { int cval; stringstream hex_str; hex_str.put(in.get()); hex_str.put(in.get()); if(hex_str >> hex >> cval) c = (char)cval; else { in.setstate(istream::failbit); c = EOF; } } } return in; } istream& Request::ParseModel(istream& in) { char c; int id, amount; int minc = 0, maxc = 0; cache_model.Clear(); while(in.good()) { GetCodedChar(in, c); if(c == ',') continue; else if(c == '&') { in.unget(); break; } else if(c == '[') { if(in >> minc) { maxc = minc; if(in.peek() == '-') in.ignore(1) >> maxc; if(!GetCodedChar(in, c) || (c != ']')) in.setstate(istream::failbit); TRACE("Model updating: [" << minc << "-" << maxc << "]"); } } else if(c == '-') { ERROR("Subtractive bin-descriptors are not supported for model updating"); in.setstate(istream::failbit); } else { if((c == 'H') && (in.peek() == 'm')) { in.ignore(1); c = 'h'; } else { in >> id; } amount = INT_MAX; if(in.peek() == ':') { if(in.ignore(1).peek() != 'L') in >> amount; else { ERROR("Number of layers can not be used for model updating"); in.setstate(istream::failbit); } } if(in) { if(c == 'M') { cache_model.AddToMetadata(id, amount); TRACE("Model updating: M" << id << ":" << (amount == INT_MAX ? -1 : amount)); } else { for(int i = minc; i <= maxc; i++) { CacheModel::Codestream& cod = cache_model.GetCodestream(i); if(c == 'h') { cod.AddToMainHeader(amount); TRACE("Model updating: Hm" << ":" << (amount == INT_MAX ? -1 : amount)); } else if(c == 'H') { cod.AddToTileHeader(amount); TRACE("Model updating: H" << id << ":" << (amount == INT_MAX ? -1 : amount)); } else if(c == 'P') { cod.AddToPrecinct(id, amount); TRACE("Model updating: P" << id << ":" << (amount == INT_MAX ? -1 : amount)); } else { ERROR("The bin-descriptor '" << c << "' is not supported for model updating"); in.setstate(istream::failbit); break; } } } } } } return in; } } esajpip-0.1~bzr33/src/jpip/woi.cc0000644000175000017500000000002212335423210016564 0ustar mathieumathieu#include "woi.h" esajpip-0.1~bzr33/src/jpip/request.h0000644000175000017500000001100612335423210017324 0ustar mathieumathieu#ifndef _JPIP_REQUEST_H_ #define _JPIP_REQUEST_H_ #include #include #include #include "jpip/woi.h" #include "jpip/cache_model.h" #include "http/request.h" #include "jpeg2000/point.h" #include "jpeg2000/coding_parameters.h" #include namespace jpip { using namespace std; using namespace jpeg2000; /** * Class derived from the HTTP Request class * that contains the required code for properly analyzing * a JPIP request, when this protocol is used over the HTTP. * * @see http::Request * @see CacheModel */ class Request :public http::Request { public: /** * Parses a cache model from an input stream. * @param stream Input stream. * @return The same input stream after the parsing. */ istream& ParseModel(istream& stream); /** * Gets a coded char from an input stream. * @param in Input stream. * @param c Reference to store the char. * @return The same input stream. */ istream& GetCodedChar(istream& in, char& c); /** * Parses the parameters of a CGI HTTP request. * @param stream Input stream. */ virtual void ParseParameters(istream& stream); /** * Parses one parameter of a CGI HTTP request. * @param stream Input stream. * @param param String to store the parameter name. * @param value String to store the parameter value. */ virtual void ParseParameter(istream& stream, const string& param, string& value); /** * Union used to control the presence of the different * JPIP parameters in a request. */ union ParametersMask { /** * Parameters mask. */ struct { int fsiz : 1; int roff : 1; int rsiz : 1; int metareq : 1; int len : 1; int target : 1; int cid : 1; int cnew : 1; int cclose : 1; int model : 1; int stream : 1; int context : 1; } items; /** * Parameters mask as integer. */ int value; /** * Initializes the mask to zero. */ ParametersMask() { value = 0; } /** * Returns true if the mask * contains the parameters associated to * the WOI (fsiz, roff and rsiz). */ bool HasWOI() const { return (value & 7); } /** * Sets the mask to zero. */ void Clear() { value = 0; } }; /** * Enumeration of the possible round directions * of a WOI for specifying the resolution levels. */ enum RoundDirection { ROUNDUP, ///< Round-up ROUNDDOWN, ///< Round-down CLOSEST ///< Closest }; Size woi_size; ///< WOI size Point woi_position; ///< WOI position int min_codestream; ///< Minimum codestream int max_codestream; ///< Maximum codestream int length_response; ///< Maximum response length ParametersMask mask; ///< Parameters mask Size resolution_size; ///< Size of the resolution level CacheModel cache_model; ///< Cache model /** * Round direction. */ RoundDirection round_direction; /** * Empty constructor. */ Request() { } /** * Obtains the resolution level and modifies the given WOI to adjust it * according to that level. * @param coding_parameters Associated coding parameters. * @param woi WOI to modify. */ void GetResolution(const CodingParameters::Ptr& coding_parameters, WOI *woi) const { Size res_image_size; if(round_direction == Request::CLOSEST) woi->resolution = coding_parameters->GetClosestResolution(resolution_size, &res_image_size); else if(round_direction == Request::ROUNDUP) woi->resolution = coding_parameters->GetRoundUpResolution(resolution_size, &res_image_size); else if(round_direction == Request::ROUNDDOWN) woi->resolution = coding_parameters->GetRoundDownResolution(resolution_size, &res_image_size); if (resolution_size != res_image_size) { woi->position.x = ceil((woi->position.x * res_image_size.x) / resolution_size.x); woi->position.y = ceil((woi->position.y * res_image_size.y) / resolution_size.y); woi->size.x = ceil((woi->size.x * res_image_size.x) / resolution_size.x); woi->size.y = ceil((woi->size.y * res_image_size.y) / resolution_size.y); } } virtual ~Request() { } }; } #endif /* _JPIP_REQUEST_H_ */ esajpip-0.1~bzr33/src/base.h0000644000175000017500000000251412335423210015610 0ustar mathieumathieu#ifndef _BASE_H_ #define _BASE_H_ #include #include #include /** * Contains a set of useful static methods used by the application. */ struct base { /** * Converts a value to a string. * @param val Value to convert. */ template static std::string to_string(TYPE val) { std::ostringstream oss; oss << val; return oss.str(); } /** * Copies a vector. */ template static void copy(std::vector& dest, const std::vector& src) { dest.clear(); for (typename std::vector::const_iterator i = src.begin(); i != src.end(); i++) dest.push_back(*i); } /** * Copies a vector of vectors. */ template static void copy(std::vector< std::vector >& dest, const std::vector< std::vector >& src) { int n = 0; dest.clear(); dest.resize(src.size()); for (typename std::vector< std::vector >::const_iterator i = src.begin(); i != src.end(); i++) base::copy(dest[n++], *i); } /** * Copies a multimap. */ template static void copy(std::multimap& dest, const std::multimap& src) { dest.clear(); for (typename std::multimap::const_iterator i = src.begin(); i != src.end(); i++) dest.insert(*i); } }; #endif /* _BASE_H_ */ esajpip-0.1~bzr33/src/net/0000755000175000017500000000000012335423210015311 5ustar mathieumathieuesajpip-0.1~bzr33/src/net/address.cc0000644000175000017500000000002612335423210017243 0ustar mathieumathieu#include "address.h" esajpip-0.1~bzr33/src/net/net.h0000644000175000017500000000030212335423210016243 0ustar mathieumathieu#ifndef _NET_NET_H_ #define _NET_NET_H_ /** * Contains classes to easy the utilization of sockets, * specially implemented for UNIX systems. */ namespace net { } #endif /* _NET_NET_H_ */ esajpip-0.1~bzr33/src/net/socket.h0000644000175000017500000001652412335423210016762 0ustar mathieumathieu#ifndef _NET_SOCKET_H__ #define _NET_SOCKET_H__ #include #include #include #include #include #include #include #include #include #include #include "address.h" namespace net { using namespace std; /** This class has been designed to work with UNIX sockets in an easy and object oriented way. */ class Socket { protected: int sid; ///< Socket id public: /** Initializes the socket id with an invalid value. */ Socket() { sid = -1; } /** Initializes the socket id with an integer value. */ Socket(int s) { sid = s; } /** * Copy constructor. */ Socket(const Socket& xs) { sid = xs.sid; } /** This operator allows to work directly with UNIX socket API. */ operator int() const { return sid; } /** @return true if the identifier has a valid value. */ bool IsValid() const { return (sid != -1); } /** Copy asignment. */ Socket& operator=(int nsid) { sid = nsid; return *this; } /** This method creates a new Internet socket, storing its identifier in the object. @param type Socket type, SOCK_STREAM by default. @return true if successful. */ bool OpenInet(int type = SOCK_STREAM) { return ((sid = socket(PF_INET, type, 0)) != -1); } /** This method creates a new UNIX socket, storing its identifier in the object. @param type Socket type, SOCK_STREAM by default. @return true if successful. */ bool OpenUnix(int type = SOCK_STREAM) { return ((sid = socket(PF_UNIX, type, 0)) != -1); } /** Configures the socket for listening incoming connections. @param address Address used to listen. @param nstack Maximum number of clients in listening stack. @return true if successful. */ bool ListenAt(const Address& address, int nstack = 10) { int flags = 1; setsockopt(sid, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); if(::bind(sid, address.GetSockAddr(), address.GetSize()) != 0) return false; if(listen(sid, nstack) != 0) return false; return true; } /** Connects the socket to a server. @param to_address Address to connect. @return true if successful. */ bool ConnectTo(const Address& to_address) { return (connect(sid, to_address.GetSockAddr(), to_address.GetSize()) == 0); } /** * Binds the socket to the specified address. * @param address Address to bind. * @return true if successful. */ bool BindTo(const Address& address) { return !::bind(sid, address.GetSockAddr(), address.GetSize()); } /** If it is a server socket, it accepts a new connection. @param from_address Pointer to store the client address. @return The integer identifier (file descriptor) of the new socket. */ int Accept(Address *from_address) { socklen_t len = from_address->GetSize(); return accept(sid, from_address->GetSockAddr(), &len); } /** Set the blocking mode of the send/receive operations. By default, this mode is true. @param state Blocking mode state to set. @return A reference of the same object. */ Socket& SetBlockingMode(bool state = true); /** @return The blocking mode of the send/receive operations. */ bool IsBlockingMode(); /** Receives a number of bytes. This methods allows to prevent blocking, without having into account the default blocking mode stablished. @param buf Buffer where to store the received bytes. @param len Length of the buffer. @param prevent_block true if blocking will be prevented. @return The number of received bytes. */ int Receive(void *buf, int len, bool prevent_block = false); /** Receives a number of bytes. This methods allows to prevent blocking, without having into account the default blocking mode stablished. @param address Pointer to store the from address. @param buf Buffer where to store the received bytes. @param len Length of the buffer. @param prevent_block true if blocking will be prevented. @return The number of received bytes. */ int ReceiveFrom(Address *address, void *buf, int len, bool prevent_block = false); /** Sends a number of bytes. This methods allows to prevent blocking, without having into account the default blocking mode stablished. @param buf Buffer with the bytes to sent. @param len Number of bytes to sent. @param prevent_block true if blocking will be prevented. @return The number of sent bytes. */ int Send(void *buf, int len, bool prevent_block = false); /** Sends a number of bytes to a specific address. This methods allows to prevent blocking, without having into account the default blocking mode established. @param address Address to send the bytes. @param buf Buffer with the bytes to sent. @param len Number of bytes to sent. @param prevent_block true if blocking will be prevented. @return The number of sent bytes. */ int SendTo(const Address& address, void *buf, int len, bool prevent_block = false); /** * Sends a descriptor through the socket. * @param address Address of the socket to send the descriptor. * @param fd File descriptor. * @param aux Auxiliary information to send attached. * @return true if successful. */ bool SendDescriptor(const Address& address, int fd, int aux = 0); /** * Returns true if the sockets is valid, that is, * if after a polling regarding error status is not successful. */ bool IsValid(); /** * Waits until input data is available (POLLIN). * @param time_out Time out (infinite by default). * @return The value returned by the poll function. */ int WaitForInput(int time_out = -1); /** * Waits until output data can be sent (POLLOUT). * @param time_out Time out (infinite by default). * @return The value returned by the poll function. */ int WaitForOutput(int time_out = -1); /** * Configures the parameter TCP_NODELAY of the * socket. * @param val New value for the parameter (1 by default). * @return true if successful. */ bool SetNoDelay(int val = 1) { return !setsockopt(sid, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); } /** * Receives a descriptor from a socket. * @param fd Variable to store the received descriptor. * @param aux Auxiliary information received attached. * @return true if successful. */ bool ReceiveDescriptor(int *fd, int *aux = NULL); /** Closes the socket. */ void Close() { if(sid != -1) close(sid); sid = -1; } /** The destructor does not closes the socket!. */ ~Socket() { } }; } #endif esajpip-0.1~bzr33/src/net/socket_stream.h0000644000175000017500000000534212335423210020331 0ustar mathieumathieu#ifndef _NET_SOCKET_STREAM_H_ #define _NET_SOCKET_STREAM_H_ #include #include #include #include "socket.h" namespace net { /** * Class derived from the STL std::streambuf to allow * streaming with sockets. See the documentation related to this * STL base class to understand the behaviour of the class * SocketBuffer. * * @see std::streambuf * @see Socket */ class SocketBuffer: public std::streambuf { protected: int sum; int in_len; int out_len; char *in_buf; char *out_buf; Socket socket; public: enum { INPUT_BUFFER_LENGTH = 500, OUTPUT_BUFFER_LENGTH = 500 }; SocketBuffer(int sid, int in_len = INPUT_BUFFER_LENGTH, int out_len = OUTPUT_BUFFER_LENGTH) :socket(sid) { sum = 0; this->in_len = in_len; this->out_len = out_len; in_buf = new char[in_len]; out_buf = new char[out_len]; setp(out_buf, out_buf + out_len); } virtual int sync() { if(pptr() != pbase()) { int n, len = 0; while(pbase() + len < pptr()) { n = socket.Send(pbase() + len, pptr() - pbase() - len); if(n >= 0) len += n; else return -1; } setp(out_buf, out_buf + out_len); } return 0; } virtual int_type underflow() { sum += (egptr() - eback()); int len = socket.Receive(in_buf, in_len); if(len <= 0) return traits_type::eof(); else { setg(in_buf, in_buf, in_buf + len); return traits_type::to_int_type(*gptr()); } } virtual int_type overflow(int_type c = EOF) { if(traits_type::eq_int_type(traits_type::eof(), c)) return sync(); else { if(pptr() == epptr()) sync(); traits_type::assign(*pptr(), traits_type::to_char_type(c)); pbump(1); return c; } } int GetReadBytes() const { return (sum + (egptr() - eback())); } Socket *GetSocket() { return &socket; } virtual ~SocketBuffer() { delete [] in_buf; delete [] out_buf; } }; /** * Class derived from std::iostream and * SocketBuffer that represents a socket stream. * * @see std::iostream * @see SocketBuffer */ class SocketStream :public SocketBuffer, public std::iostream { public: SocketStream(int sid, int in_len = INPUT_BUFFER_LENGTH, int out_len = OUTPUT_BUFFER_LENGTH) :SocketBuffer(sid, in_len, out_len), std::iostream(this) { } Socket *operator->() { return &(socket); } virtual ~SocketStream() { } }; } #endif /* _NET_SOCKET_STREAM_H_ */ esajpip-0.1~bzr33/src/net/socket_stream.cc0000644000175000017500000000003512335423210020461 0ustar mathieumathieu#include "socket_stream.h" esajpip-0.1~bzr33/src/net/socket.cc0000644000175000017500000000731312335423210017114 0ustar mathieumathieu#include #include #include #include #include #include #include #include #include "socket.h" #include "poll_table.h" #ifndef POLLRDHUP #define POLLRDHUP (0) #endif namespace net { Socket& Socket::SetBlockingMode(bool state) { int cur = fcntl(sid, F_GETFL, 0); if(state) cur |= O_NONBLOCK; else if(cur & O_NONBLOCK) cur ^= O_NONBLOCK; fcntl(sid, F_SETFL, cur); return *this; } bool Socket::IsBlockingMode() { int cur = fcntl(sid, F_GETFL, 0); return (cur & O_NONBLOCK); } bool Socket::IsValid() { PollFD poll_fd(sid, POLLRDHUP | POLLERR | POLLHUP | POLLNVAL); return (poll(&poll_fd, 1, 0) == 0); } int Socket::WaitForInput(int time_out) { PollFD poll_fd(sid, POLLIN); return poll(&poll_fd, 1, time_out); } int Socket::WaitForOutput(int time_out) { PollFD poll_fd(sid, POLLOUT); return poll(&poll_fd, 1, time_out); } int Socket::Receive(void *buf, int len, bool prevent_block) { if(!prevent_block) return recv(sid, buf, len, 0); PollFD poll_fd(sid, POLLIN); if(poll(&poll_fd, 1, 0) <= 0) return -1; return recv(sid, buf, len, 0); } int Socket::ReceiveFrom(Address *address, void *buf, int len, bool prevent_block) { socklen_t sock_len = address->GetSize(); if(!prevent_block) return recvfrom(sid, buf, len, 0, address->GetSockAddr(), &sock_len); PollFD poll_fd(sid, POLLIN); if(poll(&poll_fd, 1, 0) <= 0) return -1; return recvfrom(sid, buf, len, 0, address->GetSockAddr(), &sock_len); } int Socket::Send(void *buf, int len, bool prevent_block) { if(!prevent_block) return send(sid, buf, len, 0); PollFD poll_fd(sid, POLLOUT); if(poll(&poll_fd, 1, 0) <= 0) return -1; return send(sid, buf, len, 0); } int Socket::SendTo(const Address& address, void *buf, int len, bool prevent_block) { if(!prevent_block) return sendto(sid, buf, len, 0, address.GetSockAddr(), address.GetSize()); PollFD poll_fd(sid, POLLOUT); if(poll(&poll_fd, 1, 0) <= 0) return -1; return sendto(sid, buf, len, 0, address.GetSockAddr(), address.GetSize()); } bool Socket::SendDescriptor(const Address& address, int fd, int aux) { msghdr msg; cmsghdr *cmsg; char ccmsg[50]; assert(sizeof(ccmsg) >= CMSG_SPACE(sizeof(int))); struct iovec vec; vec.iov_base = &aux; vec.iov_len = sizeof(aux); msg.msg_name = address.GetSockAddr(); msg.msg_namelen = address.GetSize(); msg.msg_iov = &vec; msg.msg_iovlen = 1; msg.msg_control = ccmsg; msg.msg_controllen = CMSG_SPACE(sizeof(int)); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); *(int*)CMSG_DATA(cmsg) = fd; msg.msg_controllen = cmsg->cmsg_len; msg.msg_flags = 0; return (sendmsg(sid, &msg, 0) != -1); } bool Socket::ReceiveDescriptor(int *fd, int *aux) { msghdr msg; cmsghdr *cmsg; char ccmsg[50]; assert(sizeof(ccmsg) >= CMSG_SPACE(sizeof(int))); int aux2; iovec iov; if(aux) { iov.iov_base = aux; iov.iov_len = sizeof(*aux); } else { iov.iov_base = &aux2; iov.iov_len = sizeof(aux2); } msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ccmsg; msg.msg_controllen = CMSG_SPACE(sizeof(int)); if(recvmsg(sid, &msg, 0) <= 0) return false; cmsg = CMSG_FIRSTHDR(&msg); if(!cmsg) return false; if(cmsg->cmsg_type != SCM_RIGHTS) return false; *fd = *(int*)CMSG_DATA(cmsg); return true; } } esajpip-0.1~bzr33/src/net/address.h0000644000175000017500000001217212335423210017112 0ustar mathieumathieu#ifndef _NET_ADDRESS_H_ #define _NET_ADDRESS_H_ #include #include #include #include #include #include #include #include #include namespace net { using namespace std; /** * Abstract base class to wrap the sockaddr * derived structures. This class is the base of the * address classes. * * @see InetAddress * @see UnixAddress */ class Address { public: /** * Empty constructor. */ Address() { } /** * Returns a pointer to a sockaddr structure. */ virtual sockaddr *GetSockAddr() const = 0; /** * Returns the size in bytes of the sockaddr * structure returned by the previous method. */ virtual int GetSize() const = 0; /** * Empty destructor. */ virtual ~Address() { } }; /** * Class to identify and handle an Internet address. The * used internal address structure is sockaddr_in. * * @see Address */ class InetAddress :public Address { private: sockaddr_in sock_addr; ///< Internal address structure public: /** * Initializes the address to zero. */ InetAddress() { memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; } /** * Copy constructor. */ InetAddress(const InetAddress& address) { memcpy(&sock_addr, &(address.sock_addr), sizeof(sock_addr)); } /** * Initializes the address with given port. The used path * is INADDR_ANY. * @param port Port number. */ InetAddress(int port) { memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = INADDR_ANY; sock_addr.sin_port = htons((u_short)port); } /** * Initializes the address with the given path and port. * @param path Address path. * @param port Port number. */ InetAddress(const char *path, int port) { memset(&sock_addr, 0, sizeof(sock_addr)); hostent *hp = NULL; unsigned long addr; if(inet_addr(path) == INADDR_NONE) hp = gethostbyname(path); else { addr = inet_addr(path); hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); } if(hp != NULL) { sock_addr.sin_family = AF_INET; sock_addr.sin_port = htons(port); sock_addr.sin_addr.s_addr = *((unsigned long *)hp->h_addr); } } /** * Copy assignment. */ InetAddress& operator=(const InetAddress& address) { memcpy(&sock_addr, &(address.sock_addr), sizeof(sock_addr)); return *this; } /** * Overloaded from the base class to use the * internal address structure. */ virtual sockaddr *GetSockAddr() const { return (sockaddr *)&sock_addr; } /** * Overloaded from the base class to use the * internal address structure. */ virtual int GetSize() const { return sizeof(sock_addr); } /** * Returns the address path. */ string GetPath() const { return inet_ntoa(sock_addr.sin_addr); } /** * Returns the port number. */ int GetPort() const { return ntohs(sock_addr.sin_port); } }; /** * Class to identify and handle an UNIX address. The * used internal address structure is sockaddr_un. * * @see Address */ class UnixAddress :public Address { private: sockaddr_un sock_addr; ///< Internal address structure public: /** * Initializes the address to zero. */ UnixAddress() { memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sun_family = AF_UNIX; } /** * Copy constructor. */ UnixAddress(const UnixAddress& address) { memcpy(&sock_addr, &(address.sock_addr), sizeof(sock_addr)); } /** * Initializes the address with given path. * @param path Address path. */ UnixAddress(const char *path) { memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sun_family = AF_UNIX; strncpy(sock_addr.sun_path, path, sizeof(sock_addr.sun_path) - 1); } /** * Copy assignment. */ UnixAddress& operator=(const UnixAddress& address) { memcpy(&sock_addr, &(address.sock_addr), sizeof(sock_addr)); return *this; } /** * Removes the file associated to the UNIX address. */ UnixAddress& Reset() { unlink(sock_addr.sun_path); return *this; } /** * Overloaded from the base class to use the * internal address structure. */ virtual sockaddr *GetSockAddr() const { return (sockaddr *)&sock_addr; } /** * Overloaded from the base class to use the * internal address structure. */ virtual int GetSize() const { return sizeof(sock_addr); } /** * Returns the address path. */ string GetPath() const { return sock_addr.sun_path; } }; } #endif /* _NET_ADDRESS_H_ */ esajpip-0.1~bzr33/src/net/poll_table.cc0000644000175000017500000000003112335423210017727 0ustar mathieumathieu#include "poll_table.h" esajpip-0.1~bzr33/src/net/poll_table.h0000644000175000017500000000470012335423210017600 0ustar mathieumathieu#ifndef _NET_POLL_TABLE_H_ #define _NET_POLL_TABLE_H_ #include #include #include namespace net { using namespace std; /** * Wrapper structure for the structure pollfd * used by the kernel poll functions. * * @see PollTable */ struct PollFD: pollfd { /** * Initializes the structure. * @param vfd File descriptor. * @param mask Poll mask. */ PollFD(int vfd, int mask) { fd = vfd; events = mask; revents = 0; } /** * Returns true if the file descriptor * is the same as the given value. */ bool operator==(int n) { return (fd == n); } }; /** * This class allows to perfom polls easily over a vector of * descriptors. It uses an internal STL vector of PollFD * objects to handle dinamically the file descriptors * and masks. * * @see PollFD */ class PollTable { private: /** * Vector with the file descriptors and masks for polling. */ vector fds; public: PollTable() { } /** * Adds a new file descriptor and mask to the vector. * @param fd File descriptor. * @param mask Polling mask. */ void Add(int fd, int mask) { fds.push_back(PollFD(fd, mask)); } /** * Peforms a poll over all the descriptors using the * associated masks. * @param timeout Time out of the poll (infinite by default). * @return The value given by the kernel function poll. */ int Poll(int timeout = -1) { return poll(&(fds[0]), (int)fds.size(), timeout); } /** * Returns the size of the internal vector. */ int GetSize() const { return fds.size(); } /** * Removes an item of the internal vector giving its * file descriptor. * @param fd File descriptor to remove. */ void Remove(int fd) { vector::iterator i = find(fds.begin(), fds.end(), fd); if(i != fds.end()) fds.erase(i); } /** * Remove an item of the internal vector giving its * index position. * @param n Position of the item to remove. */ void RemoveAt(int n) { fds.erase(fds.begin() + n); } /** * Indexing operator. */ PollFD& operator[](int n) { return fds[n]; } virtual ~PollTable() { } }; } #endif /* _NET_POLL_TABLE_H_ */ esajpip-0.1~bzr33/src/client_manager.h0000644000175000017500000000241612335423210017647 0ustar mathieumathieu#ifndef _CLIENT_MANAGER_H_ #define _CLIENT_MANAGER_H_ #include "app_info.h" #include "app_config.h" #include "client_info.h" #include "jpeg2000/index_manager.h" using namespace jpeg2000; /** * Handles a client connection with a dedicated * thread. */ class ClientManager { private: AppConfig& cfg; ///< Application configuration AppInfo& app_info; ///< Application run-time information IndexManager& index_manager; ///< Index manager public: /** * Initializes the object. * @param _cfg Application configuration. * @param _app_info Application run-time information. * @param _index_manager Index manager. */ ClientManager( AppConfig& _cfg, AppInfo& _app_info, IndexManager& _index_manager) : cfg(_cfg), app_info(_app_info), index_manager(_index_manager) { } /** * Starts the handling of a client connection. * @param client_info Client information. */ void Run(ClientInfo *client_info); /** * Starts the handling of a client connection * but it does not do anything. This method is * used for testing the architecture of the * server. * @param client_info Client information. */ void RunBasic(ClientInfo *client_info); virtual ~ClientManager() { } }; #endif /* _CLIENT_MANAGER_H_ */ esajpip-0.1~bzr33/src/client_info.cc0000644000175000017500000000003112335423210017315 0ustar mathieumathieu#include "client_info.h" esajpip-0.1~bzr33/src/trace.h0000644000175000017500000000435612335423210016002 0ustar mathieumathieu#ifndef _TRACE_H_ #define _TRACE_H_ #include #include #define LOG4CPP_FIX_ERROR_COLLISION 1 #include #include #include #include /** * Wrapper used by the application to handle the log/trace * messages by means of the log4cpp library. */ class TraceSystem { private: log4cpp::Category *category; log4cpp::Appender *appender; log4cpp::PatternLayout *layout; log4cpp::Appender *file_appender; log4cpp::PatternLayout *file_layout; static TraceSystem traceSystem; TraceSystem(); virtual ~TraceSystem(); bool AppendToFile_(const char *name); public: static bool AppendToFile(const char *name) { return traceSystem.AppendToFile_(name); } static bool AppendToFile(const std::string& name) { return traceSystem.AppendToFile_(name.c_str()); } static log4cpp::CategoryStream logStream() { return traceSystem.category->infoStream(); } static log4cpp::CategoryStream errorStream() { return traceSystem.category->errorStream(); } static log4cpp::CategoryStream traceStream() { return traceSystem.category->debugStream(); } }; #define _RED "31m" #define _GREEN "32m" #define _YELLOW "33m" #define _BLUE "34m" #ifndef NO_COLORS #define _SET_COLOR(a) "\033[" a #define _RESET_COLOR() "\033[0m" #else #define _SET_COLOR(a) "" #define _RESET_COLOR() "" #endif #ifndef SILENT_MODE #define LOG(a) (TraceSystem::logStream() << a << log4cpp::eol) #define LOGC(c, a) (TraceSystem::logStream() << _SET_COLOR(c) << a << _RESET_COLOR() << log4cpp::eol) #define ERROR(a) (TraceSystem::errorStream() << _SET_COLOR(_RED) << __FILE__ << ":" << __LINE__ << ": ERROR: " << a << _RESET_COLOR() << log4cpp::eol) #else #define LOG(a) {} #define LOGC(c, a) {} #define ERROR(a) {} #endif #if defined(SHOW_TRACES) && !defined(NDEBUG) && !defined(SILENT_MODE) #define TRACE(a) (TraceSystem::traceStream() << _SET_COLOR(_YELLOW) << __FILE__ << ":" << __LINE__ << ": TRACE: " << a << _RESET_COLOR() << log4cpp::eol) #else #define TRACE(a) {} #endif #define CERR(a) (cerr << _SET_COLOR(_RED) << a << "!" << _RESET_COLOR() << endl, -1) #endif esajpip-0.1~bzr33/src/esa_jpip_server.cc0000644000175000017500000001602312335423210020214 0ustar mathieumathieu#ifdef _PLATFORM_LINUX #include #endif #include #include #include "trace.h" #include "version.h" #include "app_info.h" #include "app_config.h" #include "args_parser.h" #include "client_info.h" #include "client_manager.h" #include "net/poll_table.h" #include "net/socket_stream.h" #include "jpeg2000/file_manager.h" #include "jpeg2000/index_manager.h" using namespace std; using namespace net; using namespace jpeg2000; #define SERVER_NAME "ESA JPIP Server" #define SERVER_APP_NAME "esa_jpip_server" #define CONFIG_FILE "server.cfg" #ifndef POLLRDHUP #define POLLRDHUP (0) #endif AppConfig cfg; int base_id = 0; AppInfo app_info; Socket child_socket; PollTable poll_table; bool child_lost = false; IndexManager index_manager; UnixAddress child_address("/tmp/child_unix_address"); UnixAddress father_address("/tmp/father_unix_address"); int ChildProcess(); void *ClientThread(void *arg); bool ParseArguments(int argc, char **argv); void SIGCHLD_handler(int signal) { wait(NULL); child_lost = true; } int main(int argc, char **argv) { int res, fd; char cfgMark; string cfgName; Socket father_socket; InetAddress from_addr; InetAddress listen_addr; Socket listen_socket, new_conn; if(!app_info.Init()) return CERR("The shared information can not be set"); cfgMark = '-'; cfgName = CONFIG_FILE; if(File::Exists("/etc/esajpip/" CONFIG_FILE)) { cfgName = "/etc/esajpip/" CONFIG_FILE; cfgMark = ' '; } if (!cfg.Load(cfgName.c_str())) return CERR("The configuration file '" << cfgName << "' can not be read"); if(!ArgsParser(cfg, app_info).Parse(argc, argv)) return -1; if(app_info.is_running()) return CERR("The server is already running"); if(!index_manager.Init(cfg.images_folder(), cfg.caching_folder())) return CERR("The index manager can not be initialized"); app_info->father_pid = getpid(); cout << endl << SERVER_NAME << " " << VERSION << endl; cout << endl << cfgMark << cfg << endl; if (cfg.logging()) TraceSystem::AppendToFile(cfg.logging_folder() + SERVER_APP_NAME); if (!File::Exists(cfg.caching_folder().c_str())) ERROR("The cache folder does not exist"); if(cfg.address().size() <= 0) listen_addr = InetAddress(cfg.port()); else listen_addr = InetAddress(cfg.address().c_str(), cfg.port()); if (!listen_socket.OpenInet()) ERROR("The server listen socket can not be created"); else if (!listen_socket.ListenAt(listen_addr)) ERROR("The server listen socket can not be initialized"); else { LOG(SERVER_NAME << " started" << cfgMark); signal(SIGCHLD, SIG_IGN); poll_table.Add(listen_socket, POLLIN); if(!father_socket.OpenUnix(SOCK_DGRAM)) { ERROR("The father unix socket can not be created"); return -1; } if(!father_socket.BindTo(father_address.Reset())) { ERROR("The father unix socket can not be bound"); return -1; } poll_table.Add(father_socket, POLLIN); father_begin: if (!fork()) return ChildProcess(); else { signal(SIGCHLD, SIGCHLD_handler); for (;;) { res = poll_table.Poll(); if (child_lost) { child_lost = false; goto father_begin; } if(res > 0) { if (poll_table[0].revents & POLLIN) { new_conn = listen_socket.Accept(&from_addr); if (!new_conn.IsValid()) ERROR("Problems accepting a new connection"); else { if(app_info->num_connections >= cfg.max_connections()) { LOG("Refusing a connection because the limit has been reached"); new_conn.Close(); } else { LOG("New connection from " << from_addr.GetPath() << ":" << from_addr.GetPort() << " [" << (int)new_conn << "]"); if(!father_socket.SendDescriptor(child_address, new_conn, new_conn)) { ERROR("The new socket can not be sent to the child process"); new_conn.Close(); } else { poll_table.Add(new_conn, POLLRDHUP | POLLERR | POLLHUP | POLLNVAL); app_info->num_connections++; } } } } if(poll_table[1].revents & POLLIN) { father_socket.Receive(&fd, sizeof(int)); LOG("Closing the connection [" << fd << "] from child"); app_info->num_connections--; poll_table.Remove(fd); close(fd); } for(int i = 2; i < poll_table.GetSize(); i++) { if (poll_table[i].revents) { LOG("Closing the connection [" << poll_table[i].fd << "]"); app_info->num_connections--; close(poll_table[i].fd); poll_table.RemoveAt(i); } } if(app_info->num_connections < 0) app_info->num_connections = 0; } } } } listen_socket.Close(); return 0; } int ChildProcess() { int sock, father_sock; pthread_t service_tid; ClientInfo *client_info; app_info->child_iterations++; app_info->child_pid = getpid(); signal(SIGPIPE, SIG_IGN); #ifdef _PLATFORM_LINUX prctl(PR_SET_PDEATHSIG, SIGHUP); #endif LOG("Child process created (PID = " << getpid() << ")"); if(!child_socket.OpenUnix(SOCK_DGRAM)) { ERROR("The child unix socket can not be created"); return -1; } if(!child_socket.BindTo(child_address.Reset())) { ERROR("The child unix socket can not be bound"); return -1; } for (int i = 2; i < poll_table.GetSize(); i++) { sock = poll_table[i].fd; client_info = new ClientInfo(0, sock, sock); LOG("Creating a client thread for the old connection [" << sock << "]"); if (pthread_create(&service_tid, NULL, ClientThread, client_info) == -1) { ERROR("A new client thread for the old connection [" << sock << "] can not be created"); delete client_info; return -1; } pthread_detach(service_tid); } for (;;) { child_socket.ReceiveDescriptor(&sock, &father_sock); client_info = new ClientInfo(base_id++, sock, father_sock); LOG("Creating a client thread for the new connection [" << sock << "|" << father_sock << "]"); if (pthread_create(&service_tid, NULL, ClientThread, client_info) == -1) { LOG("A new client thread for the new connection [" << sock << "|" << father_sock << "] can not be created"); delete client_info; return -1; } pthread_detach(service_tid); } return 0; } void *ClientThread(void *arg) { int sock, res; ClientInfo *client_info = (ClientInfo *)arg; #ifndef BASIC_SERVER ClientManager(cfg, app_info, index_manager).Run(client_info); #else ClientManager(cfg, app_info, index_manager).RunBasic(client_info); #endif sock = client_info->father_sock(); res = child_socket.SendTo(father_address, &sock, sizeof(int)); if(res < (int)sizeof(int)) ERROR("The connection [" << sock << "] could not be closed"); delete client_info; pthread_exit(0); } esajpip-0.1~bzr33/VERSION0000644000175000017500000000000412335423210014776 0ustar mathieumathieu0.2 esajpip-0.1~bzr33/.project0000644000175000017500000000444712335423210015414 0ustar mathieumathieu esa_jpip_server org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd false org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature esajpip-0.1~bzr33/COPYRIGHT0000644000175000017500000003776712335423210015253 0ustar mathieumathieuCOMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 1. Definitions. 1.1. "Contributor" means each individual or entity that creates or contributes to the creation of Modifications. 1.2. "Contributor Version" means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. 1.3. "Covered Software" means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. 1.4. "Executable" means the Covered Software in any form other than Source Code. 1.5. "Initial Developer" means the individual or entity that first makes Original Software available under this License. 1.6. "Larger Work" means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. 1.7. "License" means this document. 1.8. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. "Modifications" means the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License. 1.10. "Original Software" means the Source Code and Executable form of computer software code that is originally released under this License. 1.11. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.12. "Source Code" means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. 1.13. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants. 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. 2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. 3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. 3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. 3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients' rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient's rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.6. Larger Works. You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. 4. Versions of the License. 4.1. New Versions. Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. 4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. 4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. 5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 6. TERMINATION. 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as "Participant") alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. 6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. 7. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 8. U.S. GOVERNMENT END USERS. The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" (as that term is defined at 48 C.F.R. ¤ 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. 9. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction's conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. 10. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. esajpip-0.1~bzr33/README0000644000175000017500000000116212335423210014614 0ustar mathieumathieuESA JPIP server Open source implementation of a JPIP server for Linux platforms. Its main goal is to be used with the Helioviewer project in order to serve the image data (more than a terabyte per day) provided by the NASA's Solar Dynamics Observatory (http://sdo.gsfc.nasa.gov/). Wiki about the Helioviewer project: http://wiki.helioviewer.org/wiki/ Information about JPEG 2000 and JPIP: http://www.jpeg.org/jpeg2000/ The compilation and installation instructions can be found in the related documentation, which is generated with "make doc" (latex and doxygen packages are required) and located at doc/refman.pdf. esajpip-0.1~bzr33/Makefile0000644000175000017500000000522112335423210015374 0ustar mathieumathieuDEBUG=YES #PLATFORM=MAC PLATFORM=LINUX #PLATFORM=SOLARIS CXX=g++ SHELL=/bin/bash OBJS += data/serialize \ data/file \ data/file_segment \ data/vint_vector OBJS += jpeg2000/point \ jpeg2000/coding_parameters \ jpeg2000/index_manager \ jpeg2000/image_index \ jpeg2000/packet_index \ jpeg2000/codestream_index \ jpeg2000/image_info \ jpeg2000/file_manager \ jpeg2000/packet \ jpeg2000/place_holder \ jpeg2000/meta_data \ jpeg2000/range OBJS += ipc/ipc_object \ ipc/event \ ipc/mutex \ ipc/rdwr_lock OBJS += http/protocol \ http/response \ http/header \ http/request OBJS += net/socket \ net/socket_stream \ net/poll_table OBJS += jpip/jpip \ jpip/woi \ jpip/request \ jpip/woi_composer \ jpip/databin_writer \ jpip/cache_model \ jpip/databin_server OBJS += base \ trace \ app_info \ app_config \ args_parser \ client_info \ client_manager ifeq ($(DEBUG),YES) FLAGS = -g -Wall -fmessage-length=0 -I src else FLAGS = -O2 -Wall -fmessage-length=0 -I src -DNDEBUG endif LIBS = -lpthread -lm -lconfig++ -llog4cpp ifeq ($(PLATFORM),LINUX) LIBS += -lrt endif ifeq ($(PLATFORM),SOLARIS) LIBS += -lrt -lnsl -lsocket FLAGS += -D_NO_DIRENT -D_NO_READPROC FLAGS += -D_USE_BOOST -D_NO_FAST_FILE endif ifeq ($(PLATFORM),MAC) FLAGS += -D_NO_READPROC -D_NO_TR1 -Wno-unused-private-field FLAGS += -D_NO_FAST_FILE -I /opt/local/include/ LIBS += -L /opt/local/lib/ endif FLAGS += -D_PLATFORM_${PLATFORM} MAIN = packet_information \ basic_server \ esa_jpip_server obj/%.o: src/%.cc src/%.h mkdir -p obj/$$(dirname $*.cc) $(CXX) $(FLAGS) -c src/$*.cc -o obj/$*.o bin/esa_jpip_server: src/esa_jpip_server.cc $(OBJS:%=obj/%.o) src/version.h mkdir -p bin $(CXX) $(FLAGS) src/esa_jpip_server.cc -o $@ $(OBJS:%=obj/%.o) $(LIBS) bin/basic_server: src/esa_jpip_server.cc $(OBJS:%=obj/%.o) src/version.h mkdir -p bin $(CXX) $(FLAGS) -DBASIC_SERVER src/esa_jpip_server.cc -o $@ $(OBJS:%=obj/%.o) $(LIBS) bin/packet_information: src/packet_information.cc $(OBJS:%=obj/%.o) mkdir -p bin $(CXX) $(FLAGS) src/packet_information.cc -o $@ $(OBJS:%=obj/%.o) $(LIBS) src/version.h: VERSION (n=$$(cat VERSION); echo "#define VERSION \"$$n\""> src/version.h) doc: documentation documentation: make -C doc all: $(MAIN:%=bin/%) clean: rm -rf obj bin log/* src/version.h make -C doc clean esajpip-0.1~bzr33/server.cfg0000644000175000017500000000051212335423210015721 0ustar mathieumathieulisten_at = { port = ${SWHV_PORT_JPIP}; address = ""; }; folders = { images = "${SWHV_DIR_IMAGE}"; caching = "${SWHV_DIR_CACHE}"; logging = "${SWHV_DIR_LOG}"; }; connections = { time_out = 60; max_number = 500; }; general = { logging = 1; log_requests = 1; cache_max_time = -1; max_chunk_size = 4000; };