1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <precomp.h>
29 #include <toolkit/out_position.hxx>
30 
31 
32 // NOT FULLY DEFINED SERVICES
33 
34 
35 
36 namespace output
37 {
38 
39 
40 
41 namespace
42 {
43 
44 const int       C_nAssumedMaxLinkLength = 500;
45 
46 void				move_ToParent(
47                         Node * &		    io_node,
48                         intt                i_levels = 1 );
49 
50 void
51 move_ToParent( Node * &   io_node,
52                intt       i_levels )
53 {
54     for ( intt n = 0; n < i_levels; ++n )
55     {
56         csv_assert(io_node != 0);
57         io_node = io_node->Parent();
58     }
59 }
60 
61 
62 
63 }   // namepace anonymous
64 
65 
66 
67 Position::Position()
68     :   sFile(),
69         pDirectory(&Node::Null_())
70 {
71 }
72 
73 
74 Position::Position( Node &              i_directory,
75                     const String &      i_file )
76     :   sFile(i_file),
77         pDirectory(&i_directory)
78 {
79 }
80 
81 Position::Position( const Position &    i_directory,
82                     const String &      i_sDifferentFile )
83     :   sFile(i_sDifferentFile),
84         pDirectory(i_directory.pDirectory)
85 {
86 }
87 
88 
89 Position::~Position()
90 {
91 }
92 
93 
94 Position &
95 Position::operator=( Node & i_node )
96 {
97     pDirectory = &i_node;
98     sFile.clear();
99     return *this;
100 }
101 
102 Position &
103 Position::operator+=( const String & i_nodeName )
104 {
105     csv_assert(pDirectory != 0);
106 
107     pDirectory = &pDirectory->Provide_Child(i_nodeName);
108     sFile.clear();
109 
110     return *this;
111 }
112 
113 Position &
114 Position::operator-=( intt i_levels )
115 {
116     csv_assert(pDirectory != 0);
117 
118     for ( intt i = i_levels; i > 0; --i )
119     {
120         pDirectory = pDirectory->Parent();
121         if (pDirectory == 0)
122         {
123             pDirectory = &Node::Null_();
124             i = 0;
125         }
126     }
127     sFile.clear();
128 
129     return *this;
130 }
131 
132 String
133 Position::LinkToRoot( const String & ) const
134 {
135     StreamLock sl(C_nAssumedMaxLinkLength);
136     return sl() << get_UpLink(Depth()) << c_str;
137 }
138 
139 void
140 Position::Get_LinkTo( StreamStr &         o_result,
141                       const Position &    i_destination,
142                       const String &      i_localLabel ) const
143 {
144     Node * p1 = pDirectory;
145     Node * p2 = i_destination.pDirectory;
146 
147     intt diff = Depth() - i_destination.Depth();
148     intt pathLength1 = 0;
149     intt pathLength2 = 0;
150 
151     if ( diff > 0 )
152     {
153         pathLength1 = diff;
154         move_ToParent(p1,pathLength1);
155     }
156     else if ( diff < 0 )
157     {
158         pathLength2 = -diff;
159         move_ToParent(p2,pathLength2);
160     }
161 
162     while ( p1 != p2 )
163     {
164         move_ToParent(p1);
165         move_ToParent(p2);
166         ++pathLength1;
167         ++pathLength2;
168     }
169 
170     o_result << get_UpLink(pathLength1);
171     i_destination.pDirectory->Get_Path(o_result, pathLength2);
172     o_result << i_destination.sFile;
173     if (i_localLabel.length())
174         o_result << "#" << i_localLabel;
175 }
176 
177 void
178 Position::Get_LinkToRoot( StreamStr &         o_result,
179                           const String &      ) const
180 {
181     o_result << get_UpLink(Depth());
182 }
183 
184 void
185 Position::Set( Node &           i_node,
186                const String &   i_file )
187 {
188     sFile = i_file;
189     pDirectory = &i_node;
190 }
191 
192 
193 
194 
195 const char *
196 get_UpLink(uintt i_depth)
197 {
198     static const uintt
199         C_nMaxDepth = 30;
200     static const char
201         C_sUpLinkArray[3*C_nMaxDepth+1] =
202                         "../../../../../../../../../../"
203                         "../../../../../../../../../../"
204                         "../../../../../../../../../../";
205     static const char *
206         C_sUpLink = &C_sUpLinkArray[0];
207 
208     if ( i_depth <= C_nMaxDepth )
209     {
210         return C_sUpLink + 3*(C_nMaxDepth - i_depth);
211     }
212     else
213     {   // not THREAD fast
214         static std::vector<char>
215             aRet;
216     	uintt nNeededSize = i_depth * 3 + 1;
217 
218         if (aRet.size() < nNeededSize)
219         {
220             aRet.resize(nNeededSize);
221             char * pEnd = &aRet[nNeededSize-1];
222             *pEnd = '\0';
223 
224             for ( char * pFill = &(*aRet.begin());
225                   pFill != pEnd;
226                   pFill += 3 )
227             {
228                 memcpy(pFill, C_sUpLink, 3);
229             }
230         }   // end if
231 
232         return &aRet[aRet.size() - 1 - 3*i_depth];
233     }
234 }
235 
236 
237 
238 
239 }   // namespace output
240