1251881Speter/* fs_skels.c --- conversion between fs native types and skeletons
2251881Speter *
3251881Speter * ====================================================================
4251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
5251881Speter *    or more contributor license agreements.  See the NOTICE file
6251881Speter *    distributed with this work for additional information
7251881Speter *    regarding copyright ownership.  The ASF licenses this file
8251881Speter *    to you under the Apache License, Version 2.0 (the
9251881Speter *    "License"); you may not use this file except in compliance
10251881Speter *    with the License.  You may obtain a copy of the License at
11251881Speter *
12251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
13251881Speter *
14251881Speter *    Unless required by applicable law or agreed to in writing,
15251881Speter *    software distributed under the License is distributed on an
16251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17251881Speter *    KIND, either express or implied.  See the License for the
18251881Speter *    specific language governing permissions and limitations
19251881Speter *    under the License.
20251881Speter * ====================================================================
21251881Speter */
22251881Speter
23251881Speter#include <string.h>
24251881Speter
25251881Speter#include <apr_md5.h>
26251881Speter#include <apr_sha1.h>
27251881Speter
28251881Speter#include "svn_error.h"
29251881Speter#include "svn_string.h"
30251881Speter#include "svn_types.h"
31251881Speter#include "svn_time.h"
32251881Speter
33251881Speter#include "private/svn_skel.h"
34251881Speter#include "private/svn_dep_compat.h"
35251881Speter#include "private/svn_subr_private.h"
36251881Speter
37251881Speter#include "svn_checksum.h"
38251881Speter#include "fs_skels.h"
39251881Speter#include "../id.h"
40251881Speter
41251881Speter
42251881Speterstatic svn_error_t *
43251881Speterskel_err(const char *skel_type)
44251881Speter{
45251881Speter  return svn_error_createf(SVN_ERR_FS_MALFORMED_SKEL, NULL,
46251881Speter                           "Malformed%s%s skeleton",
47251881Speter                           skel_type ? " " : "",
48251881Speter                           skel_type ? skel_type : "");
49251881Speter}
50251881Speter
51251881Speter
52251881Speter
53251881Speter/*** Validity Checking ***/
54251881Speter
55251881Speterstatic svn_boolean_t
56251881Speteris_valid_checksum_skel(svn_skel_t *skel)
57251881Speter{
58251881Speter  if (svn_skel__list_length(skel) != 2)
59251881Speter    return FALSE;
60251881Speter
61251881Speter  if (svn_skel__matches_atom(skel->children, "md5")
62251881Speter      && skel->children->next->is_atom)
63251881Speter    return TRUE;
64251881Speter
65251881Speter  if (svn_skel__matches_atom(skel->children, "sha1")
66251881Speter      && skel->children->next->is_atom)
67251881Speter    return TRUE;
68251881Speter
69251881Speter  return FALSE;
70251881Speter}
71251881Speter
72251881Speter
73251881Speterstatic svn_boolean_t
74251881Speteris_valid_revision_skel(svn_skel_t *skel)
75251881Speter{
76251881Speter  int len = svn_skel__list_length(skel);
77251881Speter
78251881Speter  if ((len == 2)
79251881Speter      && svn_skel__matches_atom(skel->children, "revision")
80251881Speter      && skel->children->next->is_atom)
81251881Speter    return TRUE;
82251881Speter
83251881Speter  return FALSE;
84251881Speter}
85251881Speter
86251881Speter
87251881Speterstatic svn_boolean_t
88251881Speteris_valid_transaction_skel(svn_skel_t *skel, transaction_kind_t *kind)
89251881Speter{
90251881Speter  int len = svn_skel__list_length(skel);
91251881Speter
92251881Speter  if (len != 5)
93251881Speter    return FALSE;
94251881Speter
95251881Speter  /* Determine (and verify) the kind. */
96251881Speter  if (svn_skel__matches_atom(skel->children, "transaction"))
97251881Speter    *kind = transaction_kind_normal;
98251881Speter  else if (svn_skel__matches_atom(skel->children, "committed"))
99251881Speter    *kind = transaction_kind_committed;
100251881Speter  else if (svn_skel__matches_atom(skel->children, "dead"))
101251881Speter    *kind = transaction_kind_dead;
102251881Speter  else
103251881Speter    return FALSE;
104251881Speter
105251881Speter  if (skel->children->next->is_atom
106251881Speter      && skel->children->next->next->is_atom
107251881Speter      && (! skel->children->next->next->next->is_atom)
108251881Speter      && (! skel->children->next->next->next->next->is_atom))
109251881Speter    return TRUE;
110251881Speter
111251881Speter  return FALSE;
112251881Speter}
113251881Speter
114251881Speter
115251881Speterstatic svn_boolean_t
116251881Speteris_valid_rep_delta_chunk_skel(svn_skel_t *skel)
117251881Speter{
118251881Speter  int len;
119251881Speter  svn_skel_t *window;
120251881Speter  svn_skel_t *diff;
121251881Speter
122251881Speter  /* check the delta skel. */
123251881Speter  if ((svn_skel__list_length(skel) != 2)
124251881Speter      || (! skel->children->is_atom))
125251881Speter    return FALSE;
126251881Speter
127251881Speter  /* check the window. */
128251881Speter  window = skel->children->next;
129251881Speter  len = svn_skel__list_length(window);
130251881Speter  if ((len < 3) || (len > 4))
131251881Speter    return FALSE;
132251881Speter  if (! ((! window->children->is_atom)
133251881Speter         && (window->children->next->is_atom)
134251881Speter         && (window->children->next->next->is_atom)))
135251881Speter    return FALSE;
136251881Speter  if ((len == 4)
137251881Speter      && (! window->children->next->next->next->is_atom))
138251881Speter    return FALSE;
139251881Speter
140251881Speter  /* check the diff. ### currently we support only svndiff version
141251881Speter     0 delta data. */
142251881Speter  diff = window->children;
143251881Speter  if ((svn_skel__list_length(diff) == 3)
144251881Speter      && (svn_skel__matches_atom(diff->children, "svndiff"))
145251881Speter      && ((svn_skel__matches_atom(diff->children->next, "0"))
146251881Speter          || (svn_skel__matches_atom(diff->children->next, "1")))
147251881Speter      && (diff->children->next->next->is_atom))
148251881Speter    return TRUE;
149251881Speter
150251881Speter  return FALSE;
151251881Speter}
152251881Speter
153251881Speter
154251881Speterstatic svn_boolean_t
155251881Speteris_valid_representation_skel(svn_skel_t *skel)
156251881Speter{
157251881Speter  int len = svn_skel__list_length(skel);
158251881Speter  svn_skel_t *header;
159251881Speter  int header_len;
160251881Speter
161251881Speter  /* the rep has at least two items in it, a HEADER list, and at least
162251881Speter     one piece of kind-specific data. */
163251881Speter  if (len < 2)
164251881Speter    return FALSE;
165251881Speter
166251881Speter  /* check the header.  it must have KIND and TXN atoms, and
167251881Speter     optionally 1 or 2 checksums (which is a list form). */
168251881Speter  header = skel->children;
169251881Speter  header_len = svn_skel__list_length(header);
170251881Speter  if (! (((header_len == 2)     /* 2 means old repository, checksum absent */
171251881Speter          && (header->children->is_atom)
172251881Speter          && (header->children->next->is_atom))
173251881Speter         || ((header_len == 3)  /* 3 means md5 checksum present */
174251881Speter             && (header->children->is_atom)
175251881Speter             && (header->children->next->is_atom)
176251881Speter             && (is_valid_checksum_skel(header->children->next->next)))
177251881Speter         || ((header_len == 4)  /* 3 means md5 and sha1 checksums present */
178251881Speter             && (header->children->is_atom)
179251881Speter             && (header->children->next->is_atom)
180251881Speter             && (is_valid_checksum_skel(header->children->next->next))
181251881Speter             && (is_valid_checksum_skel(header->children->next->next->next)))))
182251881Speter    return FALSE;
183251881Speter
184251881Speter  /* check for fulltext rep. */
185251881Speter  if ((len == 2)
186251881Speter      && (svn_skel__matches_atom(header->children, "fulltext")))
187251881Speter    return TRUE;
188251881Speter
189251881Speter  /* check for delta rep. */
190251881Speter  if ((len >= 2)
191251881Speter      && (svn_skel__matches_atom(header->children, "delta")))
192251881Speter    {
193251881Speter      /* it's a delta rep.  check the validity.  */
194251881Speter      svn_skel_t *chunk = skel->children->next;
195251881Speter
196251881Speter      /* loop over chunks, checking each one. */
197251881Speter      while (chunk)
198251881Speter        {
199251881Speter          if (! is_valid_rep_delta_chunk_skel(chunk))
200251881Speter            return FALSE;
201251881Speter          chunk = chunk->next;
202251881Speter        }
203251881Speter
204251881Speter      /* all good on this delta rep. */
205251881Speter      return TRUE;
206251881Speter    }
207251881Speter
208251881Speter  return FALSE;
209251881Speter}
210251881Speter
211251881Speter
212251881Speterstatic svn_boolean_t
213251881Speteris_valid_node_revision_header_skel(svn_skel_t *skel, svn_skel_t **kind_p)
214251881Speter{
215251881Speter  int len = svn_skel__list_length(skel);
216251881Speter
217251881Speter  if (len < 2)
218251881Speter    return FALSE;
219251881Speter
220251881Speter  /* set the *KIND_P pointer. */
221251881Speter  *kind_p = skel->children;
222251881Speter
223251881Speter  /* check for valid lengths. */
224251881Speter  if (! ((len == 2) || (len == 3) || (len == 4) || (len == 6)))
225251881Speter    return FALSE;
226251881Speter
227251881Speter  /* got mergeinfo stuff? */
228251881Speter  if ((len > 4)
229251881Speter      && (! (skel->children->next->next->next->next->is_atom
230251881Speter             && skel->children->next->next->next->next->next->is_atom)))
231251881Speter    return FALSE;
232251881Speter
233251881Speter  /* got predecessor count? */
234251881Speter  if ((len > 3)
235251881Speter      && (! skel->children->next->next->next->is_atom))
236251881Speter    return FALSE;
237251881Speter
238251881Speter  /* got predecessor? */
239251881Speter  if ((len > 2)
240251881Speter      && (! skel->children->next->next->is_atom))
241251881Speter    return FALSE;
242251881Speter
243251881Speter  /* got the basics? */
244251881Speter  if (! (skel->children->is_atom
245251881Speter         && skel->children->next->is_atom
246251881Speter         && (skel->children->next->data[0] == '/')))
247251881Speter    return FALSE;
248251881Speter
249251881Speter  return TRUE;
250251881Speter}
251251881Speter
252251881Speter
253251881Speterstatic svn_boolean_t
254251881Speteris_valid_node_revision_skel(svn_skel_t *skel)
255251881Speter{
256251881Speter  int len = svn_skel__list_length(skel);
257251881Speter  svn_skel_t *header = skel->children;
258251881Speter  svn_skel_t *kind;
259251881Speter
260251881Speter  if (len < 1)
261251881Speter    return FALSE;
262251881Speter
263251881Speter  if (! is_valid_node_revision_header_skel(header, &kind))
264251881Speter    return FALSE;
265251881Speter
266251881Speter  if (svn_skel__matches_atom(kind, "dir"))
267251881Speter    {
268251881Speter      if (! ((len == 3)
269251881Speter             && header->next->is_atom
270251881Speter             && header->next->next->is_atom))
271251881Speter        return FALSE;
272251881Speter    }
273251881Speter  else if (svn_skel__matches_atom(kind, "file"))
274251881Speter    {
275251881Speter      if (len < 3)
276251881Speter        return FALSE;
277251881Speter
278251881Speter      if (! header->next->is_atom)
279251881Speter        return FALSE;
280251881Speter
281251881Speter      /* As of SVN_FS_BASE__MIN_REP_SHARING_FORMAT version, the
282251881Speter         DATA-KEY slot can be a 2-tuple. */
283251881Speter      if (! header->next->next->is_atom)
284251881Speter        {
285251881Speter          if (! ((svn_skel__list_length(header->next->next) == 2)
286251881Speter                 && header->next->next->children->is_atom
287251881Speter                 && header->next->next->children->len
288251881Speter                 && header->next->next->children->next->is_atom
289251881Speter                 && header->next->next->children->next->len))
290251881Speter            return FALSE;
291251881Speter        }
292251881Speter
293251881Speter      if ((len > 3) && (! header->next->next->next->is_atom))
294251881Speter        return FALSE;
295251881Speter
296251881Speter      if (len > 4)
297251881Speter        return FALSE;
298251881Speter    }
299251881Speter
300251881Speter  return TRUE;
301251881Speter}
302251881Speter
303251881Speter
304251881Speterstatic svn_boolean_t
305251881Speteris_valid_copy_skel(svn_skel_t *skel)
306251881Speter{
307251881Speter  return ((svn_skel__list_length(skel) == 4)
308251881Speter          && (svn_skel__matches_atom(skel->children, "copy")
309251881Speter              || svn_skel__matches_atom(skel->children, "soft-copy"))
310251881Speter          && skel->children->next->is_atom
311251881Speter          && skel->children->next->next->is_atom
312251881Speter          && skel->children->next->next->next->is_atom);
313251881Speter}
314251881Speter
315251881Speter
316251881Speterstatic svn_boolean_t
317251881Speteris_valid_change_skel(svn_skel_t *skel, svn_fs_path_change_kind_t *kind)
318251881Speter{
319251881Speter  if ((svn_skel__list_length(skel) == 6)
320251881Speter      && svn_skel__matches_atom(skel->children, "change")
321251881Speter      && skel->children->next->is_atom
322251881Speter      && skel->children->next->next->is_atom
323251881Speter      && skel->children->next->next->next->is_atom
324251881Speter      && skel->children->next->next->next->next->is_atom
325251881Speter      && skel->children->next->next->next->next->next->is_atom)
326251881Speter    {
327251881Speter      svn_skel_t *kind_skel = skel->children->next->next->next;
328251881Speter
329251881Speter      /* check the kind (and return it) */
330251881Speter      if (svn_skel__matches_atom(kind_skel, "reset"))
331251881Speter        {
332251881Speter          if (kind)
333251881Speter            *kind = svn_fs_path_change_reset;
334251881Speter          return TRUE;
335251881Speter        }
336251881Speter      if (svn_skel__matches_atom(kind_skel, "add"))
337251881Speter        {
338251881Speter          if (kind)
339251881Speter            *kind = svn_fs_path_change_add;
340251881Speter          return TRUE;
341251881Speter        }
342251881Speter      if (svn_skel__matches_atom(kind_skel, "delete"))
343251881Speter        {
344251881Speter          if (kind)
345251881Speter            *kind = svn_fs_path_change_delete;
346251881Speter          return TRUE;
347251881Speter        }
348251881Speter      if (svn_skel__matches_atom(kind_skel, "replace"))
349251881Speter        {
350251881Speter          if (kind)
351251881Speter            *kind = svn_fs_path_change_replace;
352251881Speter          return TRUE;
353251881Speter        }
354251881Speter      if (svn_skel__matches_atom(kind_skel, "modify"))
355251881Speter        {
356251881Speter          if (kind)
357251881Speter            *kind = svn_fs_path_change_modify;
358251881Speter          return TRUE;
359251881Speter        }
360251881Speter    }
361251881Speter  return FALSE;
362251881Speter}
363251881Speter
364251881Speter
365251881Speterstatic svn_boolean_t
366251881Speteris_valid_lock_skel(svn_skel_t *skel)
367251881Speter{
368251881Speter  if ((svn_skel__list_length(skel) == 8)
369251881Speter      && svn_skel__matches_atom(skel->children, "lock")
370251881Speter      && skel->children->next->is_atom
371251881Speter      && skel->children->next->next->is_atom
372251881Speter      && skel->children->next->next->next->is_atom
373251881Speter      && skel->children->next->next->next->next->is_atom
374251881Speter      && skel->children->next->next->next->next->next->is_atom
375251881Speter      && skel->children->next->next->next->next->next->next->is_atom
376251881Speter      && skel->children->next->next->next->next->next->next->next->is_atom)
377251881Speter    return TRUE;
378251881Speter
379251881Speter  return FALSE;
380251881Speter}
381251881Speter
382251881Speter
383251881Speter
384251881Speter/*** Parsing (conversion from skeleton to native FS type) ***/
385251881Speter
386251881Spetersvn_error_t *
387251881Spetersvn_fs_base__parse_revision_skel(revision_t **revision_p,
388251881Speter                                 svn_skel_t *skel,
389251881Speter                                 apr_pool_t *pool)
390251881Speter{
391251881Speter  revision_t *revision;
392251881Speter
393251881Speter  /* Validate the skel. */
394251881Speter  if (! is_valid_revision_skel(skel))
395251881Speter    return skel_err("revision");
396251881Speter
397251881Speter  /* Create the returned structure */
398251881Speter  revision = apr_pcalloc(pool, sizeof(*revision));
399251881Speter  revision->txn_id = apr_pstrmemdup(pool, skel->children->next->data,
400251881Speter                                    skel->children->next->len);
401251881Speter
402251881Speter  /* Return the structure. */
403251881Speter  *revision_p = revision;
404251881Speter  return SVN_NO_ERROR;
405251881Speter}
406251881Speter
407251881Speter
408251881Spetersvn_error_t *
409251881Spetersvn_fs_base__parse_transaction_skel(transaction_t **transaction_p,
410251881Speter                                    svn_skel_t *skel,
411251881Speter                                    apr_pool_t *pool)
412251881Speter{
413251881Speter  transaction_t *transaction;
414251881Speter  transaction_kind_t kind;
415251881Speter  svn_skel_t *root_id, *base_id_or_rev, *proplist, *copies;
416251881Speter  int len;
417251881Speter
418251881Speter  /* Validate the skel. */
419251881Speter  if (! is_valid_transaction_skel(skel, &kind))
420251881Speter    return skel_err("transaction");
421251881Speter
422251881Speter  root_id = skel->children->next;
423251881Speter  base_id_or_rev = skel->children->next->next;
424251881Speter  proplist = skel->children->next->next->next;
425251881Speter  copies = skel->children->next->next->next->next;
426251881Speter
427251881Speter  /* Create the returned structure */
428251881Speter  transaction = apr_pcalloc(pool, sizeof(*transaction));
429251881Speter
430251881Speter  /* KIND */
431251881Speter  transaction->kind = kind;
432251881Speter
433251881Speter  /* REVISION or BASE-ID */
434251881Speter  if (kind == transaction_kind_committed)
435251881Speter    {
436251881Speter      /* Committed transactions have a revision number... */
437251881Speter      transaction->base_id = NULL;
438251881Speter      transaction->revision =
439251881Speter        SVN_STR_TO_REV(apr_pstrmemdup(pool, base_id_or_rev->data,
440251881Speter                                      base_id_or_rev->len));
441251881Speter      if (! SVN_IS_VALID_REVNUM(transaction->revision))
442251881Speter        return skel_err("transaction");
443251881Speter
444251881Speter    }
445251881Speter  else
446251881Speter    {
447251881Speter      /* ...where unfinished transactions have a base node-revision-id. */
448251881Speter      transaction->revision = SVN_INVALID_REVNUM;
449251881Speter      transaction->base_id = svn_fs_base__id_parse(base_id_or_rev->data,
450251881Speter                                                   base_id_or_rev->len, pool);
451251881Speter    }
452251881Speter
453251881Speter  /* ROOT-ID */
454251881Speter  transaction->root_id = svn_fs_base__id_parse(root_id->data,
455251881Speter                                               root_id->len, pool);
456251881Speter
457251881Speter  /* PROPLIST */
458251881Speter  SVN_ERR(svn_skel__parse_proplist(&(transaction->proplist),
459251881Speter                                   proplist, pool));
460251881Speter
461251881Speter  /* COPIES */
462251881Speter  if ((len = svn_skel__list_length(copies)))
463251881Speter    {
464251881Speter      const char *copy_id;
465251881Speter      apr_array_header_t *txncopies;
466251881Speter      svn_skel_t *cpy = copies->children;
467251881Speter
468251881Speter      txncopies = apr_array_make(pool, len, sizeof(copy_id));
469251881Speter      while (cpy)
470251881Speter        {
471251881Speter          copy_id = apr_pstrmemdup(pool, cpy->data, cpy->len);
472251881Speter          APR_ARRAY_PUSH(txncopies, const char *) = copy_id;
473251881Speter          cpy = cpy->next;
474251881Speter        }
475251881Speter      transaction->copies = txncopies;
476251881Speter    }
477251881Speter
478251881Speter  /* Return the structure. */
479251881Speter  *transaction_p = transaction;
480251881Speter  return SVN_NO_ERROR;
481251881Speter}
482251881Speter
483251881Speter
484251881Spetersvn_error_t *
485251881Spetersvn_fs_base__parse_representation_skel(representation_t **rep_p,
486251881Speter                                       svn_skel_t *skel,
487251881Speter                                       apr_pool_t *pool)
488251881Speter{
489251881Speter  representation_t *rep;
490251881Speter  svn_skel_t *header_skel;
491251881Speter
492251881Speter  /* Validate the skel. */
493251881Speter  if (! is_valid_representation_skel(skel))
494251881Speter    return skel_err("representation");
495251881Speter  header_skel = skel->children;
496251881Speter
497251881Speter  /* Create the returned structure */
498251881Speter  rep = apr_pcalloc(pool, sizeof(*rep));
499251881Speter
500251881Speter  /* KIND */
501251881Speter  if (svn_skel__matches_atom(header_skel->children, "fulltext"))
502251881Speter    rep->kind = rep_kind_fulltext;
503251881Speter  else
504251881Speter    rep->kind = rep_kind_delta;
505251881Speter
506251881Speter  /* TXN */
507251881Speter  rep->txn_id = apr_pstrmemdup(pool, header_skel->children->next->data,
508251881Speter                               header_skel->children->next->len);
509251881Speter
510251881Speter  /* MD5 */
511251881Speter  if (header_skel->children->next->next)
512251881Speter    {
513251881Speter      svn_skel_t *checksum_skel = header_skel->children->next->next;
514251881Speter      rep->md5_checksum =
515251881Speter        svn_checksum__from_digest_md5((const unsigned char *)
516251881Speter                                      (checksum_skel->children->next->data),
517251881Speter                                      pool);
518251881Speter
519251881Speter      /* SHA1 */
520251881Speter      if (header_skel->children->next->next->next)
521251881Speter        {
522251881Speter          checksum_skel = header_skel->children->next->next->next;
523251881Speter          rep->sha1_checksum =
524251881Speter            svn_checksum__from_digest_sha1(
525251881Speter              (const unsigned char *)(checksum_skel->children->next->data),
526251881Speter              pool);
527251881Speter        }
528251881Speter    }
529251881Speter
530251881Speter  /* KIND-SPECIFIC stuff */
531251881Speter  if (rep->kind == rep_kind_fulltext)
532251881Speter    {
533251881Speter      /* "fulltext"-specific. */
534251881Speter      rep->contents.fulltext.string_key
535251881Speter        = apr_pstrmemdup(pool,
536251881Speter                         skel->children->next->data,
537251881Speter                         skel->children->next->len);
538251881Speter    }
539251881Speter  else
540251881Speter    {
541251881Speter      /* "delta"-specific. */
542251881Speter      svn_skel_t *chunk_skel = skel->children->next;
543251881Speter      rep_delta_chunk_t *chunk;
544251881Speter      apr_array_header_t *chunks;
545251881Speter
546251881Speter      /* Alloc the chunk array. */
547251881Speter      chunks = apr_array_make(pool, svn_skel__list_length(skel) - 1,
548251881Speter                              sizeof(chunk));
549251881Speter
550251881Speter      /* Process the chunks. */
551251881Speter      while (chunk_skel)
552251881Speter        {
553251881Speter          svn_skel_t *window_skel = chunk_skel->children->next;
554251881Speter          svn_skel_t *diff_skel = window_skel->children;
555251881Speter          apr_int64_t val;
556251881Speter          apr_uint64_t uval;
557251881Speter          const char *str;
558251881Speter
559251881Speter          /* Allocate a chunk and its window */
560251881Speter          chunk = apr_palloc(pool, sizeof(*chunk));
561251881Speter
562251881Speter          /* Populate the window */
563251881Speter          str = apr_pstrmemdup(pool, diff_skel->children->next->data,
564251881Speter                               diff_skel->children->next->len);
565251881Speter          SVN_ERR(svn_cstring_strtoui64(&uval, str, 0, 255, 10));
566251881Speter          chunk->version = (apr_byte_t)uval;
567251881Speter
568251881Speter          chunk->string_key
569251881Speter            = apr_pstrmemdup(pool,
570251881Speter                             diff_skel->children->next->next->data,
571251881Speter                             diff_skel->children->next->next->len);
572251881Speter
573251881Speter          str = apr_pstrmemdup(pool, window_skel->children->next->data,
574251881Speter                               window_skel->children->next->len);
575251881Speter          SVN_ERR(svn_cstring_strtoui64(&uval, str, 0, APR_SIZE_MAX, 10));
576251881Speter          chunk->size = (apr_size_t)uval;
577251881Speter
578251881Speter          chunk->rep_key
579251881Speter            = apr_pstrmemdup(pool,
580251881Speter                             window_skel->children->next->next->data,
581251881Speter                             window_skel->children->next->next->len);
582251881Speter
583251881Speter          str = apr_pstrmemdup(pool, chunk_skel->children->data,
584251881Speter                               chunk_skel->children->len);
585251881Speter          SVN_ERR(svn_cstring_strtoi64(&val, str, 0, APR_INT64_MAX, 10));
586251881Speter          chunk->offset = (svn_filesize_t)val;
587251881Speter
588251881Speter          /* Add this chunk to the array. */
589251881Speter          APR_ARRAY_PUSH(chunks, rep_delta_chunk_t *) = chunk;
590251881Speter
591251881Speter          /* Next... */
592251881Speter          chunk_skel = chunk_skel->next;
593251881Speter        }
594251881Speter
595251881Speter      /* Add the chunks array to the representation. */
596251881Speter      rep->contents.delta.chunks = chunks;
597251881Speter    }
598251881Speter
599251881Speter  /* Return the structure. */
600251881Speter  *rep_p = rep;
601251881Speter  return SVN_NO_ERROR;
602251881Speter}
603251881Speter
604251881Speter
605251881Spetersvn_error_t *
606251881Spetersvn_fs_base__parse_node_revision_skel(node_revision_t **noderev_p,
607251881Speter                                      svn_skel_t *skel,
608251881Speter                                      apr_pool_t *pool)
609251881Speter{
610251881Speter  node_revision_t *noderev;
611251881Speter  svn_skel_t *header_skel, *cur_skel;
612251881Speter
613251881Speter  /* Validate the skel. */
614251881Speter  if (! is_valid_node_revision_skel(skel))
615251881Speter    return skel_err("node-revision");
616251881Speter  header_skel = skel->children;
617251881Speter
618251881Speter  /* Create the returned structure */
619251881Speter  noderev = apr_pcalloc(pool, sizeof(*noderev));
620251881Speter
621251881Speter  /* KIND */
622251881Speter  if (svn_skel__matches_atom(header_skel->children, "dir"))
623251881Speter    noderev->kind = svn_node_dir;
624251881Speter  else
625251881Speter    noderev->kind = svn_node_file;
626251881Speter
627251881Speter  /* CREATED-PATH */
628251881Speter  noderev->created_path = apr_pstrmemdup(pool,
629251881Speter                                         header_skel->children->next->data,
630251881Speter                                         header_skel->children->next->len);
631251881Speter
632251881Speter  /* PREDECESSOR-ID */
633251881Speter  if (header_skel->children->next->next)
634251881Speter    {
635251881Speter      cur_skel = header_skel->children->next->next;
636251881Speter      if (cur_skel->len)
637251881Speter        noderev->predecessor_id = svn_fs_base__id_parse(cur_skel->data,
638251881Speter                                                        cur_skel->len, pool);
639251881Speter
640251881Speter      /* PREDECESSOR-COUNT */
641251881Speter      noderev->predecessor_count = -1;
642251881Speter      if (cur_skel->next)
643251881Speter        {
644251881Speter          const char *str;
645251881Speter
646251881Speter          cur_skel = cur_skel->next;
647251881Speter          if (cur_skel->len)
648251881Speter            {
649251881Speter              str = apr_pstrmemdup(pool, cur_skel->data, cur_skel->len);
650251881Speter              SVN_ERR(svn_cstring_atoi(&noderev->predecessor_count, str));
651251881Speter            }
652251881Speter
653251881Speter          /* HAS-MERGEINFO and MERGEINFO-COUNT */
654251881Speter          if (cur_skel->next)
655251881Speter            {
656251881Speter              int val;
657251881Speter
658251881Speter              cur_skel = cur_skel->next;
659251881Speter              str = apr_pstrmemdup(pool, cur_skel->data, cur_skel->len);
660251881Speter              SVN_ERR(svn_cstring_atoi(&val, str));
661251881Speter              noderev->has_mergeinfo = (val != 0);
662251881Speter
663251881Speter              str = apr_pstrmemdup(pool, cur_skel->next->data,
664251881Speter                                   cur_skel->next->len);
665251881Speter              SVN_ERR(svn_cstring_atoi64(&noderev->mergeinfo_count, str));
666251881Speter            }
667251881Speter        }
668251881Speter    }
669251881Speter
670251881Speter  /* PROP-KEY */
671251881Speter  if (skel->children->next->len)
672251881Speter    noderev->prop_key = apr_pstrmemdup(pool, skel->children->next->data,
673251881Speter                                       skel->children->next->len);
674251881Speter
675251881Speter  /* DATA-KEY */
676251881Speter  if (skel->children->next->next->is_atom)
677251881Speter    {
678251881Speter      /* This is a real data rep key. */
679251881Speter      if (skel->children->next->next->len)
680251881Speter        noderev->data_key = apr_pstrmemdup(pool,
681251881Speter                                           skel->children->next->next->data,
682251881Speter                                           skel->children->next->next->len);
683251881Speter      noderev->data_key_uniquifier = NULL;
684251881Speter    }
685251881Speter  else
686251881Speter    {
687251881Speter      /* This is a 2-tuple with a data rep key and a uniquifier. */
688251881Speter      noderev->data_key =
689251881Speter        apr_pstrmemdup(pool,
690251881Speter                       skel->children->next->next->children->data,
691251881Speter                       skel->children->next->next->children->len);
692251881Speter      noderev->data_key_uniquifier =
693251881Speter        apr_pstrmemdup(pool,
694251881Speter                       skel->children->next->next->children->next->data,
695251881Speter                       skel->children->next->next->children->next->len);
696251881Speter    }
697251881Speter
698251881Speter  /* EDIT-DATA-KEY (optional, files only) */
699251881Speter  if ((noderev->kind == svn_node_file)
700251881Speter      && skel->children->next->next->next
701251881Speter      && skel->children->next->next->next->len)
702251881Speter    noderev->edit_key
703251881Speter      = apr_pstrmemdup(pool, skel->children->next->next->next->data,
704251881Speter                       skel->children->next->next->next->len);
705251881Speter
706251881Speter  /* Return the structure. */
707251881Speter  *noderev_p = noderev;
708251881Speter  return SVN_NO_ERROR;
709251881Speter}
710251881Speter
711251881Speter
712251881Spetersvn_error_t *
713251881Spetersvn_fs_base__parse_copy_skel(copy_t **copy_p,
714251881Speter                             svn_skel_t *skel,
715251881Speter                             apr_pool_t *pool)
716251881Speter{
717251881Speter  copy_t *copy;
718251881Speter
719251881Speter  /* Validate the skel. */
720251881Speter  if (! is_valid_copy_skel(skel))
721251881Speter    return skel_err("copy");
722251881Speter
723251881Speter  /* Create the returned structure */
724251881Speter  copy = apr_pcalloc(pool, sizeof(*copy));
725251881Speter
726251881Speter  /* KIND */
727251881Speter  if (svn_skel__matches_atom(skel->children, "soft-copy"))
728251881Speter    copy->kind = copy_kind_soft;
729251881Speter  else
730251881Speter    copy->kind = copy_kind_real;
731251881Speter
732251881Speter  /* SRC-PATH */
733251881Speter  copy->src_path = apr_pstrmemdup(pool,
734251881Speter                                  skel->children->next->data,
735251881Speter                                  skel->children->next->len);
736251881Speter
737251881Speter  /* SRC-TXN-ID */
738251881Speter  copy->src_txn_id = apr_pstrmemdup(pool,
739251881Speter                                    skel->children->next->next->data,
740251881Speter                                    skel->children->next->next->len);
741251881Speter
742251881Speter  /* DST-NODE-ID */
743251881Speter  copy->dst_noderev_id
744251881Speter    = svn_fs_base__id_parse(skel->children->next->next->next->data,
745251881Speter                            skel->children->next->next->next->len, pool);
746251881Speter
747251881Speter  /* Return the structure. */
748251881Speter  *copy_p = copy;
749251881Speter  return SVN_NO_ERROR;
750251881Speter}
751251881Speter
752251881Speter
753251881Spetersvn_error_t *
754251881Spetersvn_fs_base__parse_entries_skel(apr_hash_t **entries_p,
755251881Speter                                svn_skel_t *skel,
756251881Speter                                apr_pool_t *pool)
757251881Speter{
758251881Speter  apr_hash_t *entries = NULL;
759251881Speter  int len = svn_skel__list_length(skel);
760251881Speter  svn_skel_t *elt;
761251881Speter
762251881Speter  if (! (len >= 0))
763251881Speter    return skel_err("entries");
764251881Speter
765251881Speter  if (len > 0)
766251881Speter    {
767251881Speter      /* Else, allocate a hash and populate it. */
768251881Speter      entries = apr_hash_make(pool);
769251881Speter
770251881Speter      /* Check entries are well-formed as we go along. */
771251881Speter      for (elt = skel->children; elt; elt = elt->next)
772251881Speter        {
773251881Speter          const char *name;
774251881Speter          svn_fs_id_t *id;
775251881Speter
776251881Speter          /* ENTRY must be a list of two elements. */
777251881Speter          if (svn_skel__list_length(elt) != 2)
778251881Speter            return skel_err("entries");
779251881Speter
780251881Speter          /* Get the entry's name and ID. */
781251881Speter          name = apr_pstrmemdup(pool, elt->children->data,
782251881Speter                                elt->children->len);
783251881Speter          id = svn_fs_base__id_parse(elt->children->next->data,
784251881Speter                                     elt->children->next->len, pool);
785251881Speter
786251881Speter          /* Add the entry to the hash. */
787251881Speter          apr_hash_set(entries, name, elt->children->len, id);
788251881Speter        }
789251881Speter    }
790251881Speter
791251881Speter  /* Return the structure. */
792251881Speter  *entries_p = entries;
793251881Speter  return SVN_NO_ERROR;
794251881Speter}
795251881Speter
796251881Speter
797251881Spetersvn_error_t *
798251881Spetersvn_fs_base__parse_change_skel(change_t **change_p,
799251881Speter                               svn_skel_t *skel,
800251881Speter                               apr_pool_t *pool)
801251881Speter{
802251881Speter  change_t *change;
803251881Speter  svn_fs_path_change_kind_t kind;
804251881Speter
805251881Speter  /* Validate the skel. */
806251881Speter  if (! is_valid_change_skel(skel, &kind))
807251881Speter    return skel_err("change");
808251881Speter
809251881Speter  /* Create the returned structure */
810251881Speter  change = apr_pcalloc(pool, sizeof(*change));
811251881Speter
812251881Speter  /* PATH */
813251881Speter  change->path = apr_pstrmemdup(pool, skel->children->next->data,
814251881Speter                                skel->children->next->len);
815251881Speter
816251881Speter  /* NODE-REV-ID */
817251881Speter  if (skel->children->next->next->len)
818251881Speter    change->noderev_id = svn_fs_base__id_parse
819251881Speter      (skel->children->next->next->data, skel->children->next->next->len,
820251881Speter       pool);
821251881Speter
822251881Speter  /* KIND */
823251881Speter  change->kind = kind;
824251881Speter
825251881Speter  /* TEXT-MOD */
826251881Speter  if (skel->children->next->next->next->next->len)
827251881Speter    change->text_mod = TRUE;
828251881Speter
829251881Speter  /* PROP-MOD */
830251881Speter  if (skel->children->next->next->next->next->next->len)
831251881Speter    change->prop_mod = TRUE;
832251881Speter
833251881Speter  /* Return the structure. */
834251881Speter  *change_p = change;
835251881Speter  return SVN_NO_ERROR;
836251881Speter}
837251881Speter
838251881Speter
839251881Spetersvn_error_t *
840251881Spetersvn_fs_base__parse_lock_skel(svn_lock_t **lock_p,
841251881Speter                             svn_skel_t *skel,
842251881Speter                             apr_pool_t *pool)
843251881Speter{
844251881Speter  svn_lock_t *lock;
845251881Speter  const char *timestr;
846251881Speter
847251881Speter  /* Validate the skel. */
848251881Speter  if (! is_valid_lock_skel(skel))
849251881Speter    return skel_err("lock");
850251881Speter
851251881Speter  /* Create the returned structure */
852251881Speter  lock = apr_pcalloc(pool, sizeof(*lock));
853251881Speter
854251881Speter  /* PATH */
855251881Speter  lock->path = apr_pstrmemdup(pool, skel->children->next->data,
856251881Speter                              skel->children->next->len);
857251881Speter
858251881Speter  /* LOCK-TOKEN */
859251881Speter  lock->token = apr_pstrmemdup(pool,
860251881Speter                               skel->children->next->next->data,
861251881Speter                               skel->children->next->next->len);
862251881Speter
863251881Speter  /* OWNER */
864251881Speter  lock->owner = apr_pstrmemdup(pool,
865251881Speter                               skel->children->next->next->next->data,
866251881Speter                               skel->children->next->next->next->len);
867251881Speter
868251881Speter  /* COMMENT  (could be just an empty atom) */
869251881Speter  if (skel->children->next->next->next->next->len)
870251881Speter    lock->comment =
871251881Speter      apr_pstrmemdup(pool,
872251881Speter                     skel->children->next->next->next->next->data,
873251881Speter                     skel->children->next->next->next->next->len);
874251881Speter
875251881Speter  /* XML_P */
876251881Speter  if (svn_skel__matches_atom
877251881Speter      (skel->children->next->next->next->next->next, "1"))
878251881Speter    lock->is_dav_comment = TRUE;
879251881Speter  else
880251881Speter    lock->is_dav_comment = FALSE;
881251881Speter
882251881Speter  /* CREATION-DATE */
883251881Speter  timestr = apr_pstrmemdup
884251881Speter    (pool,
885251881Speter     skel->children->next->next->next->next->next->next->data,
886251881Speter     skel->children->next->next->next->next->next->next->len);
887251881Speter  SVN_ERR(svn_time_from_cstring(&(lock->creation_date),
888251881Speter                                timestr, pool));
889251881Speter
890251881Speter  /* EXPIRATION-DATE  (could be just an empty atom) */
891251881Speter  if (skel->children->next->next->next->next->next->next->next->len)
892251881Speter    {
893251881Speter      timestr =
894251881Speter        apr_pstrmemdup
895251881Speter        (pool,
896251881Speter         skel->children->next->next->next->next->next->next->next->data,
897251881Speter         skel->children->next->next->next->next->next->next->next->len);
898251881Speter      SVN_ERR(svn_time_from_cstring(&(lock->expiration_date),
899251881Speter                                    timestr, pool));
900251881Speter    }
901251881Speter
902251881Speter  /* Return the structure. */
903251881Speter  *lock_p = lock;
904251881Speter  return SVN_NO_ERROR;
905251881Speter}
906251881Speter
907251881Speter
908251881Speter
909251881Speter/*** Unparsing (conversion from native FS type to skeleton) ***/
910251881Speter
911251881Spetersvn_error_t *
912251881Spetersvn_fs_base__unparse_revision_skel(svn_skel_t **skel_p,
913251881Speter                                   const revision_t *revision,
914251881Speter                                   apr_pool_t *pool)
915251881Speter{
916251881Speter  svn_skel_t *skel;
917251881Speter
918251881Speter  /* Create the skel. */
919251881Speter  skel = svn_skel__make_empty_list(pool);
920251881Speter
921251881Speter  /* TXN_ID */
922251881Speter  svn_skel__prepend(svn_skel__str_atom(revision->txn_id, pool), skel);
923251881Speter
924251881Speter  /* "revision" */
925251881Speter  svn_skel__prepend(svn_skel__str_atom("revision", pool), skel);
926251881Speter
927251881Speter  /* Validate and return the skel. */
928251881Speter  if (! is_valid_revision_skel(skel))
929251881Speter    return skel_err("revision");
930251881Speter  *skel_p = skel;
931251881Speter  return SVN_NO_ERROR;
932251881Speter}
933251881Speter
934251881Speter
935251881Spetersvn_error_t *
936251881Spetersvn_fs_base__unparse_transaction_skel(svn_skel_t **skel_p,
937251881Speter                                      const transaction_t *transaction,
938251881Speter                                      apr_pool_t *pool)
939251881Speter{
940251881Speter  svn_skel_t *skel;
941251881Speter  svn_skel_t *proplist_skel, *copies_skel, *header_skel;
942251881Speter  svn_string_t *id_str;
943251881Speter  transaction_kind_t kind;
944251881Speter
945251881Speter  /* Create the skel. */
946251881Speter  skel = svn_skel__make_empty_list(pool);
947251881Speter
948251881Speter  switch (transaction->kind)
949251881Speter    {
950251881Speter    case transaction_kind_committed:
951251881Speter      header_skel = svn_skel__str_atom("committed", pool);
952251881Speter      if ((transaction->base_id)
953251881Speter          || (! SVN_IS_VALID_REVNUM(transaction->revision)))
954251881Speter        return skel_err("transaction");
955251881Speter      break;
956251881Speter    case transaction_kind_dead:
957251881Speter      header_skel = svn_skel__str_atom("dead", pool);
958251881Speter      if ((! transaction->base_id)
959251881Speter          || (SVN_IS_VALID_REVNUM(transaction->revision)))
960251881Speter        return skel_err("transaction");
961251881Speter      break;
962251881Speter    case transaction_kind_normal:
963251881Speter      header_skel = svn_skel__str_atom("transaction", pool);
964251881Speter      if ((! transaction->base_id)
965251881Speter          || (SVN_IS_VALID_REVNUM(transaction->revision)))
966251881Speter        return skel_err("transaction");
967251881Speter      break;
968251881Speter    default:
969251881Speter      return skel_err("transaction");
970251881Speter    }
971251881Speter
972251881Speter
973251881Speter  /* COPIES */
974251881Speter  copies_skel = svn_skel__make_empty_list(pool);
975251881Speter  if (transaction->copies && transaction->copies->nelts)
976251881Speter    {
977251881Speter      int i;
978251881Speter      for (i = transaction->copies->nelts - 1; i >= 0; i--)
979251881Speter        {
980251881Speter          svn_skel__prepend(svn_skel__str_atom(
981251881Speter                                APR_ARRAY_IDX(transaction->copies, i,
982251881Speter                                              const char *),
983251881Speter                                pool),
984251881Speter                            copies_skel);
985251881Speter        }
986251881Speter    }
987251881Speter  svn_skel__prepend(copies_skel, skel);
988251881Speter
989251881Speter  /* PROPLIST */
990251881Speter  SVN_ERR(svn_skel__unparse_proplist(&proplist_skel,
991251881Speter                                     transaction->proplist, pool));
992251881Speter  svn_skel__prepend(proplist_skel, skel);
993251881Speter
994251881Speter  /* REVISION or BASE-ID */
995251881Speter  if (transaction->kind == transaction_kind_committed)
996251881Speter    {
997251881Speter      /* Committed transactions have a revision number... */
998251881Speter      svn_skel__prepend(svn_skel__str_atom(apr_psprintf(pool, "%ld",
999251881Speter                                                        transaction->revision),
1000251881Speter                                           pool), skel);
1001251881Speter    }
1002251881Speter  else
1003251881Speter    {
1004251881Speter      /* ...where other transactions have a base node revision ID. */
1005251881Speter      id_str = svn_fs_base__id_unparse(transaction->base_id, pool);
1006251881Speter      svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool),
1007251881Speter                        skel);
1008251881Speter    }
1009251881Speter
1010251881Speter  /* ROOT-ID */
1011251881Speter  id_str = svn_fs_base__id_unparse(transaction->root_id, pool);
1012251881Speter  svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool), skel);
1013251881Speter
1014251881Speter  /* KIND (see above) */
1015251881Speter  svn_skel__prepend(header_skel, skel);
1016251881Speter
1017251881Speter  /* Validate and return the skel. */
1018251881Speter  if (! is_valid_transaction_skel(skel, &kind))
1019251881Speter    return skel_err("transaction");
1020251881Speter  if (kind != transaction->kind)
1021251881Speter    return skel_err("transaction");
1022251881Speter  *skel_p = skel;
1023251881Speter  return SVN_NO_ERROR;
1024251881Speter}
1025251881Speter
1026251881Speter
1027251881Speter/* Construct a skel representing CHECKSUM, allocated in POOL, and prepend
1028251881Speter * it onto the existing skel SKEL. */
1029251881Speterstatic svn_error_t *
1030251881Speterprepend_checksum(svn_skel_t *skel,
1031251881Speter                 svn_checksum_t *checksum,
1032251881Speter                 apr_pool_t *pool)
1033251881Speter{
1034251881Speter  svn_skel_t *checksum_skel = svn_skel__make_empty_list(pool);
1035251881Speter
1036251881Speter  switch (checksum->kind)
1037251881Speter    {
1038251881Speter    case svn_checksum_md5:
1039251881Speter      svn_skel__prepend(svn_skel__mem_atom(checksum->digest,
1040251881Speter                                           APR_MD5_DIGESTSIZE, pool),
1041251881Speter                        checksum_skel);
1042251881Speter      svn_skel__prepend(svn_skel__str_atom("md5", pool), checksum_skel);
1043251881Speter      break;
1044251881Speter
1045251881Speter    case svn_checksum_sha1:
1046251881Speter      svn_skel__prepend(svn_skel__mem_atom(checksum->digest,
1047251881Speter                                           APR_SHA1_DIGESTSIZE, pool),
1048251881Speter                        checksum_skel);
1049251881Speter      svn_skel__prepend(svn_skel__str_atom("sha1", pool), checksum_skel);
1050251881Speter      break;
1051251881Speter
1052251881Speter    default:
1053251881Speter      return skel_err("checksum");
1054251881Speter    }
1055251881Speter  svn_skel__prepend(checksum_skel, skel);
1056251881Speter
1057251881Speter  return SVN_NO_ERROR;
1058251881Speter}
1059251881Speter
1060251881Speter
1061251881Spetersvn_error_t *
1062251881Spetersvn_fs_base__unparse_representation_skel(svn_skel_t **skel_p,
1063251881Speter                                         const representation_t *rep,
1064251881Speter                                         int format,
1065251881Speter                                         apr_pool_t *pool)
1066251881Speter{
1067251881Speter  svn_skel_t *skel = svn_skel__make_empty_list(pool);
1068251881Speter  svn_skel_t *header_skel = svn_skel__make_empty_list(pool);
1069251881Speter
1070251881Speter  /** Some parts of the header are common to all representations; do
1071251881Speter      those parts first. **/
1072251881Speter
1073251881Speter  /* SHA1 */
1074251881Speter  if ((format >= SVN_FS_BASE__MIN_REP_SHARING_FORMAT) && rep->sha1_checksum)
1075251881Speter    SVN_ERR(prepend_checksum(header_skel, rep->sha1_checksum, pool));
1076251881Speter
1077251881Speter  /* MD5 */
1078251881Speter  {
1079251881Speter    svn_checksum_t *md5_checksum = rep->md5_checksum;
1080251881Speter    if (! md5_checksum)
1081251881Speter      md5_checksum = svn_checksum_create(svn_checksum_md5, pool);
1082251881Speter    SVN_ERR(prepend_checksum(header_skel, md5_checksum, pool));
1083251881Speter  }
1084251881Speter
1085251881Speter  /* TXN */
1086251881Speter  if (rep->txn_id)
1087251881Speter    svn_skel__prepend(svn_skel__str_atom(rep->txn_id, pool), header_skel);
1088251881Speter  else
1089251881Speter    svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel);
1090251881Speter
1091251881Speter  /** Do the kind-specific stuff. **/
1092251881Speter
1093251881Speter  if (rep->kind == rep_kind_fulltext)
1094251881Speter    {
1095251881Speter      /*** Fulltext Representation. ***/
1096251881Speter
1097251881Speter      /* STRING-KEY */
1098251881Speter      if ((! rep->contents.fulltext.string_key)
1099251881Speter          || (! *rep->contents.fulltext.string_key))
1100251881Speter        svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1101251881Speter      else
1102251881Speter        svn_skel__prepend(svn_skel__str_atom(rep->contents.fulltext.string_key,
1103251881Speter                                             pool), skel);
1104251881Speter
1105251881Speter      /* "fulltext" */
1106251881Speter      svn_skel__prepend(svn_skel__str_atom("fulltext", pool), header_skel);
1107251881Speter
1108251881Speter      /* header */
1109251881Speter      svn_skel__prepend(header_skel, skel);
1110251881Speter    }
1111251881Speter  else if (rep->kind == rep_kind_delta)
1112251881Speter    {
1113251881Speter      /*** Delta Representation. ***/
1114251881Speter      int i;
1115251881Speter      apr_array_header_t *chunks = rep->contents.delta.chunks;
1116251881Speter
1117251881Speter      /* Loop backwards through the windows, creating and prepending skels. */
1118251881Speter      for (i = chunks->nelts; i > 0; i--)
1119251881Speter        {
1120251881Speter          svn_skel_t *window_skel = svn_skel__make_empty_list(pool);
1121251881Speter          svn_skel_t *chunk_skel = svn_skel__make_empty_list(pool);
1122251881Speter          svn_skel_t *diff_skel = svn_skel__make_empty_list(pool);
1123251881Speter          const char *size_str, *offset_str, *version_str;
1124251881Speter          rep_delta_chunk_t *chunk = APR_ARRAY_IDX(chunks, i - 1,
1125251881Speter                                                   rep_delta_chunk_t *);
1126251881Speter
1127251881Speter          /* OFFSET */
1128251881Speter          offset_str = apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT,
1129251881Speter                                    chunk->offset);
1130251881Speter
1131251881Speter          /* SIZE */
1132251881Speter          size_str = apr_psprintf(pool, "%" APR_SIZE_T_FMT, chunk->size);
1133251881Speter
1134251881Speter          /* VERSION */
1135251881Speter          version_str = apr_psprintf(pool, "%d", chunk->version);
1136251881Speter
1137251881Speter          /* DIFF */
1138251881Speter          if ((! chunk->string_key) || (! *chunk->string_key))
1139251881Speter            svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), diff_skel);
1140251881Speter          else
1141251881Speter            svn_skel__prepend(svn_skel__str_atom(chunk->string_key, pool),
1142251881Speter                              diff_skel);
1143251881Speter          svn_skel__prepend(svn_skel__str_atom(version_str, pool), diff_skel);
1144251881Speter          svn_skel__prepend(svn_skel__str_atom("svndiff", pool), diff_skel);
1145251881Speter
1146251881Speter          /* REP-KEY */
1147251881Speter          if ((! chunk->rep_key) || (! *(chunk->rep_key)))
1148251881Speter            svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool),
1149251881Speter                              window_skel);
1150251881Speter          else
1151251881Speter            svn_skel__prepend(svn_skel__str_atom(chunk->rep_key, pool),
1152251881Speter                              window_skel);
1153251881Speter          svn_skel__prepend(svn_skel__str_atom(size_str, pool), window_skel);
1154251881Speter          svn_skel__prepend(diff_skel, window_skel);
1155251881Speter
1156251881Speter          /* window header. */
1157251881Speter          svn_skel__prepend(window_skel, chunk_skel);
1158251881Speter          svn_skel__prepend(svn_skel__str_atom(offset_str, pool),
1159251881Speter                               chunk_skel);
1160251881Speter
1161251881Speter          /* Add this window item to the main skel. */
1162251881Speter          svn_skel__prepend(chunk_skel, skel);
1163251881Speter        }
1164251881Speter
1165251881Speter      /* "delta" */
1166251881Speter      svn_skel__prepend(svn_skel__str_atom("delta", pool), header_skel);
1167251881Speter
1168251881Speter      /* header */
1169251881Speter      svn_skel__prepend(header_skel, skel);
1170251881Speter    }
1171251881Speter  else /* unknown kind */
1172251881Speter    SVN_ERR_MALFUNCTION();
1173251881Speter
1174251881Speter  /* Validate and return the skel. */
1175251881Speter  if (! is_valid_representation_skel(skel))
1176251881Speter    return skel_err("representation");
1177251881Speter  *skel_p = skel;
1178251881Speter  return SVN_NO_ERROR;
1179251881Speter}
1180251881Speter
1181251881Speter
1182251881Spetersvn_error_t *
1183251881Spetersvn_fs_base__unparse_node_revision_skel(svn_skel_t **skel_p,
1184251881Speter                                        const node_revision_t *noderev,
1185251881Speter                                        int format,
1186251881Speter                                        apr_pool_t *pool)
1187251881Speter{
1188251881Speter  svn_skel_t *skel;
1189251881Speter  svn_skel_t *header_skel;
1190251881Speter  const char *num_str;
1191251881Speter
1192251881Speter  /* Create the skel. */
1193251881Speter  skel = svn_skel__make_empty_list(pool);
1194251881Speter  header_skel = svn_skel__make_empty_list(pool);
1195251881Speter
1196251881Speter  /* Store mergeinfo stuffs only if the schema level supports it. */
1197251881Speter  if (format >= SVN_FS_BASE__MIN_MERGEINFO_FORMAT)
1198251881Speter    {
1199251881Speter      /* MERGEINFO-COUNT */
1200251881Speter      num_str = apr_psprintf(pool, "%" APR_INT64_T_FMT,
1201251881Speter                             noderev->mergeinfo_count);
1202251881Speter      svn_skel__prepend(svn_skel__str_atom(num_str, pool), header_skel);
1203251881Speter
1204251881Speter      /* HAS-MERGEINFO */
1205251881Speter      svn_skel__prepend(svn_skel__mem_atom(noderev->has_mergeinfo ? "1" : "0",
1206251881Speter                                           1, pool), header_skel);
1207251881Speter
1208251881Speter      /* PREDECESSOR-COUNT padding (only if we *don't* have a valid
1209251881Speter         value; if we do, we'll pick that up below) */
1210251881Speter      if (noderev->predecessor_count == -1)
1211251881Speter        {
1212251881Speter          svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel);
1213251881Speter        }
1214251881Speter    }
1215251881Speter
1216251881Speter  /* PREDECESSOR-COUNT */
1217251881Speter  if (noderev->predecessor_count != -1)
1218251881Speter    {
1219251881Speter      const char *count_str = apr_psprintf(pool, "%d",
1220251881Speter                                           noderev->predecessor_count);
1221251881Speter      svn_skel__prepend(svn_skel__str_atom(count_str, pool), header_skel);
1222251881Speter    }
1223251881Speter
1224251881Speter  /* PREDECESSOR-ID */
1225251881Speter  if (noderev->predecessor_id)
1226251881Speter    {
1227251881Speter      svn_string_t *id_str = svn_fs_base__id_unparse(noderev->predecessor_id,
1228251881Speter                                                     pool);
1229251881Speter      svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool),
1230251881Speter                        header_skel);
1231251881Speter    }
1232251881Speter  else
1233251881Speter    {
1234251881Speter      svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel);
1235251881Speter    }
1236251881Speter
1237251881Speter  /* CREATED-PATH */
1238251881Speter  svn_skel__prepend(svn_skel__str_atom(noderev->created_path, pool),
1239251881Speter                    header_skel);
1240251881Speter
1241251881Speter  /* KIND */
1242251881Speter  if (noderev->kind == svn_node_file)
1243251881Speter    svn_skel__prepend(svn_skel__str_atom("file", pool), header_skel);
1244251881Speter  else if (noderev->kind == svn_node_dir)
1245251881Speter    svn_skel__prepend(svn_skel__str_atom("dir", pool), header_skel);
1246251881Speter  else
1247251881Speter    SVN_ERR_MALFUNCTION();
1248251881Speter
1249251881Speter  /* ### do we really need to check *node->FOO_key ? if a key doesn't
1250251881Speter     ### exist, then the field should be NULL ...  */
1251251881Speter
1252251881Speter  /* EDIT-DATA-KEY (optional) */
1253251881Speter  if ((noderev->edit_key) && (*noderev->edit_key))
1254251881Speter    svn_skel__prepend(svn_skel__str_atom(noderev->edit_key, pool), skel);
1255251881Speter
1256251881Speter  /* DATA-KEY | (DATA-KEY DATA-KEY-UNIQID) */
1257251881Speter  if ((noderev->data_key_uniquifier) && (*noderev->data_key_uniquifier))
1258251881Speter    {
1259251881Speter      /* Build a 2-tuple with a rep key and uniquifier. */
1260251881Speter      svn_skel_t *data_key_skel = svn_skel__make_empty_list(pool);
1261251881Speter
1262251881Speter      /* DATA-KEY-UNIQID */
1263251881Speter      svn_skel__prepend(svn_skel__str_atom(noderev->data_key_uniquifier,
1264251881Speter                                           pool),
1265251881Speter                        data_key_skel);
1266251881Speter
1267251881Speter      /* DATA-KEY */
1268251881Speter      if ((noderev->data_key) && (*noderev->data_key))
1269251881Speter        svn_skel__prepend(svn_skel__str_atom(noderev->data_key, pool),
1270251881Speter                          data_key_skel);
1271251881Speter      else
1272251881Speter        svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), data_key_skel);
1273251881Speter
1274251881Speter      /* Add our 2-tuple to the main skel. */
1275251881Speter      svn_skel__prepend(data_key_skel, skel);
1276251881Speter    }
1277251881Speter  else
1278251881Speter    {
1279251881Speter      /* Just store the rep key (or empty placeholder) in the main skel. */
1280251881Speter      if ((noderev->data_key) && (*noderev->data_key))
1281251881Speter        svn_skel__prepend(svn_skel__str_atom(noderev->data_key, pool), skel);
1282251881Speter      else
1283251881Speter        svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1284251881Speter    }
1285251881Speter
1286251881Speter  /* PROP-KEY */
1287251881Speter  if ((noderev->prop_key) && (*noderev->prop_key))
1288251881Speter    svn_skel__prepend(svn_skel__str_atom(noderev->prop_key, pool), skel);
1289251881Speter  else
1290251881Speter    svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1291251881Speter
1292251881Speter  /* HEADER */
1293251881Speter  svn_skel__prepend(header_skel, skel);
1294251881Speter
1295251881Speter  /* Validate and return the skel. */
1296251881Speter  if (! is_valid_node_revision_skel(skel))
1297251881Speter    return skel_err("node-revision");
1298251881Speter  *skel_p = skel;
1299251881Speter  return SVN_NO_ERROR;
1300251881Speter}
1301251881Speter
1302251881Speter
1303251881Spetersvn_error_t *
1304251881Spetersvn_fs_base__unparse_copy_skel(svn_skel_t **skel_p,
1305251881Speter                               const copy_t *copy,
1306251881Speter                               apr_pool_t *pool)
1307251881Speter{
1308251881Speter  svn_skel_t *skel;
1309251881Speter  svn_string_t *tmp_str;
1310251881Speter
1311251881Speter  /* Create the skel. */
1312251881Speter  skel = svn_skel__make_empty_list(pool);
1313251881Speter
1314251881Speter  /* DST-NODE-ID */
1315251881Speter  tmp_str = svn_fs_base__id_unparse(copy->dst_noderev_id, pool);
1316251881Speter  svn_skel__prepend(svn_skel__mem_atom(tmp_str->data, tmp_str->len, pool),
1317251881Speter                    skel);
1318251881Speter
1319251881Speter  /* SRC-TXN-ID */
1320251881Speter  if ((copy->src_txn_id) && (*copy->src_txn_id))
1321251881Speter    svn_skel__prepend(svn_skel__str_atom(copy->src_txn_id, pool), skel);
1322251881Speter  else
1323251881Speter    svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1324251881Speter
1325251881Speter  /* SRC-PATH */
1326251881Speter  if ((copy->src_path) && (*copy->src_path))
1327251881Speter    svn_skel__prepend(svn_skel__str_atom(copy->src_path, pool), skel);
1328251881Speter  else
1329251881Speter    svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1330251881Speter
1331251881Speter  /* "copy" */
1332251881Speter  if (copy->kind == copy_kind_real)
1333251881Speter    svn_skel__prepend(svn_skel__str_atom("copy", pool), skel);
1334251881Speter  else
1335251881Speter    svn_skel__prepend(svn_skel__str_atom("soft-copy", pool), skel);
1336251881Speter
1337251881Speter  /* Validate and return the skel. */
1338251881Speter  if (! is_valid_copy_skel(skel))
1339251881Speter    return skel_err("copy");
1340251881Speter  *skel_p = skel;
1341251881Speter  return SVN_NO_ERROR;
1342251881Speter}
1343251881Speter
1344251881Speter
1345251881Spetersvn_error_t *
1346251881Spetersvn_fs_base__unparse_entries_skel(svn_skel_t **skel_p,
1347251881Speter                                  apr_hash_t *entries,
1348251881Speter                                  apr_pool_t *pool)
1349251881Speter{
1350251881Speter  svn_skel_t *skel = svn_skel__make_empty_list(pool);
1351251881Speter  apr_hash_index_t *hi;
1352251881Speter
1353251881Speter  /* Create the skel. */
1354251881Speter  if (entries)
1355251881Speter    {
1356251881Speter      /* Loop over hash entries */
1357251881Speter      for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
1358251881Speter        {
1359251881Speter          const void *key;
1360251881Speter          void *val;
1361251881Speter          apr_ssize_t klen;
1362251881Speter          svn_fs_id_t *value;
1363251881Speter          svn_string_t *id_str;
1364251881Speter          svn_skel_t *entry_skel = svn_skel__make_empty_list(pool);
1365251881Speter
1366251881Speter          apr_hash_this(hi, &key, &klen, &val);
1367251881Speter          value = val;
1368251881Speter
1369251881Speter          /* VALUE */
1370251881Speter          id_str = svn_fs_base__id_unparse(value, pool);
1371251881Speter          svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len,
1372251881Speter                                               pool),
1373251881Speter                            entry_skel);
1374251881Speter
1375251881Speter          /* NAME */
1376251881Speter          svn_skel__prepend(svn_skel__mem_atom(key, klen, pool), entry_skel);
1377251881Speter
1378251881Speter          /* Add entry to the entries skel. */
1379251881Speter          svn_skel__prepend(entry_skel, skel);
1380251881Speter        }
1381251881Speter    }
1382251881Speter
1383251881Speter  /* Return the skel. */
1384251881Speter  *skel_p = skel;
1385251881Speter  return SVN_NO_ERROR;
1386251881Speter}
1387251881Speter
1388251881Speter
1389251881Spetersvn_error_t *
1390251881Spetersvn_fs_base__unparse_change_skel(svn_skel_t **skel_p,
1391251881Speter                                 const change_t *change,
1392251881Speter                                 apr_pool_t *pool)
1393251881Speter{
1394251881Speter  svn_skel_t *skel;
1395251881Speter  svn_string_t *tmp_str;
1396251881Speter  svn_fs_path_change_kind_t kind;
1397251881Speter
1398251881Speter  /* Create the skel. */
1399251881Speter  skel = svn_skel__make_empty_list(pool);
1400251881Speter
1401251881Speter  /* PROP-MOD */
1402251881Speter  if (change->prop_mod)
1403251881Speter    svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
1404251881Speter  else
1405251881Speter    svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1406251881Speter
1407251881Speter  /* TEXT-MOD */
1408251881Speter  if (change->text_mod)
1409251881Speter    svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
1410251881Speter  else
1411251881Speter    svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1412251881Speter
1413251881Speter  /* KIND */
1414251881Speter  switch (change->kind)
1415251881Speter    {
1416251881Speter    case svn_fs_path_change_reset:
1417251881Speter      svn_skel__prepend(svn_skel__str_atom("reset", pool), skel);
1418251881Speter      break;
1419251881Speter    case svn_fs_path_change_add:
1420251881Speter      svn_skel__prepend(svn_skel__str_atom("add", pool), skel);
1421251881Speter      break;
1422251881Speter    case svn_fs_path_change_delete:
1423251881Speter      svn_skel__prepend(svn_skel__str_atom("delete", pool), skel);
1424251881Speter      break;
1425251881Speter    case svn_fs_path_change_replace:
1426251881Speter      svn_skel__prepend(svn_skel__str_atom("replace", pool), skel);
1427251881Speter      break;
1428251881Speter    case svn_fs_path_change_modify:
1429251881Speter    default:
1430251881Speter      svn_skel__prepend(svn_skel__str_atom("modify", pool), skel);
1431251881Speter      break;
1432251881Speter    }
1433251881Speter
1434251881Speter  /* NODE-REV-ID */
1435251881Speter  if (change->noderev_id)
1436251881Speter    {
1437251881Speter      tmp_str = svn_fs_base__id_unparse(change->noderev_id, pool);
1438251881Speter      svn_skel__prepend(svn_skel__mem_atom(tmp_str->data, tmp_str->len, pool),
1439251881Speter                        skel);
1440251881Speter    }
1441251881Speter  else
1442251881Speter    {
1443251881Speter      svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1444251881Speter    }
1445251881Speter
1446251881Speter  /* PATH */
1447251881Speter  svn_skel__prepend(svn_skel__str_atom(change->path, pool), skel);
1448251881Speter
1449251881Speter  /* "change" */
1450251881Speter  svn_skel__prepend(svn_skel__str_atom("change", pool), skel);
1451251881Speter
1452251881Speter  /* Validate and return the skel. */
1453251881Speter  if (! is_valid_change_skel(skel, &kind))
1454251881Speter    return skel_err("change");
1455251881Speter  if (kind != change->kind)
1456251881Speter    return skel_err("change");
1457251881Speter  *skel_p = skel;
1458251881Speter  return SVN_NO_ERROR;
1459251881Speter}
1460251881Speter
1461251881Speter
1462251881Spetersvn_error_t *
1463251881Spetersvn_fs_base__unparse_lock_skel(svn_skel_t **skel_p,
1464251881Speter                               const svn_lock_t *lock,
1465251881Speter                               apr_pool_t *pool)
1466251881Speter{
1467251881Speter  svn_skel_t *skel;
1468251881Speter
1469251881Speter  /* Create the skel. */
1470251881Speter  skel = svn_skel__make_empty_list(pool);
1471251881Speter
1472251881Speter  /* EXP-DATE is optional.  If not present, just use an empty atom. */
1473251881Speter  if (lock->expiration_date)
1474251881Speter    svn_skel__prepend(svn_skel__str_atom(
1475251881Speter                          svn_time_to_cstring(lock->expiration_date, pool),
1476251881Speter                          pool), skel);
1477251881Speter  else
1478251881Speter    svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1479251881Speter
1480251881Speter  /* CREATION-DATE */
1481251881Speter  svn_skel__prepend(svn_skel__str_atom(
1482251881Speter                        svn_time_to_cstring(lock->creation_date, pool),
1483251881Speter                        pool), skel);
1484251881Speter
1485251881Speter  /* XML_P */
1486251881Speter  if (lock->is_dav_comment)
1487251881Speter    svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
1488251881Speter  else
1489251881Speter    svn_skel__prepend(svn_skel__str_atom("0", pool), skel);
1490251881Speter
1491251881Speter  /* COMMENT */
1492251881Speter  if (lock->comment)
1493251881Speter    svn_skel__prepend(svn_skel__str_atom(lock->comment, pool), skel);
1494251881Speter  else
1495251881Speter    svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1496251881Speter
1497251881Speter  /* OWNER */
1498251881Speter  svn_skel__prepend(svn_skel__str_atom(lock->owner, pool), skel);
1499251881Speter
1500251881Speter  /* LOCK-TOKEN */
1501251881Speter  svn_skel__prepend(svn_skel__str_atom(lock->token, pool), skel);
1502251881Speter
1503251881Speter  /* PATH */
1504251881Speter  svn_skel__prepend(svn_skel__str_atom(lock->path, pool), skel);
1505251881Speter
1506251881Speter  /* "lock" */
1507251881Speter  svn_skel__prepend(svn_skel__str_atom("lock", pool), skel);
1508251881Speter
1509251881Speter  /* Validate and return the skel. */
1510251881Speter  if (! is_valid_lock_skel(skel))
1511251881Speter    return skel_err("lock");
1512251881Speter
1513251881Speter  *skel_p = skel;
1514251881Speter  return SVN_NO_ERROR;
1515251881Speter}
1516