1    
2    /* ====================================================================
3     * The Apache Software License, Version 1.1
4     *
5     * Copyright (c) 2002 The Apache Software Foundation.  All rights
6     * reserved.
7     *
8     * Redistribution and use in source and binary forms, with or without
9     * modification, are permitted provided that the following conditions
10    * are met:
11    *
12    * 1. Redistributions of source code must retain the above copyright
13    *    notice, this list of conditions and the following disclaimer.
14    *
15    * 2. Redistributions in binary form must reproduce the above copyright
16    *    notice, this list of conditions and the following disclaimer in
17    *    the documentation and/or other materials provided with the
18    *    distribution.
19    *
20    * 3. The end-user documentation included with the redistribution,
21    *    if any, must include the following acknowledgment:
22    *       "This product includes software developed by the
23    *        Apache Software Foundation (http://www.apache.org/)."
24    *    Alternately, this acknowledgment may appear in the software itself,
25    *    if and wherever such third-party acknowledgments normally appear.
26    *
27    * 4. The names "Apache" and "Apache Software Foundation" and
28    *    "Apache POI" must not be used to endorse or promote products
29    *    derived from this software without prior written permission. For
30    *    written permission, please contact apache@apache.org.
31    *
32    * 5. Products derived from this software may not be called "Apache",
33    *    "Apache POI", nor may "Apache" appear in their name, without
34    *    prior written permission of the Apache Software Foundation.
35    *
36    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47    * SUCH DAMAGE.
48    * ====================================================================
49    *
50    * This software consists of voluntary contributions made by many
51    * individuals on behalf of the Apache Software Foundation.  For more
52    * information on the Apache Software Foundation, please see
53    * <http://www.apache.org/>.
54    */
55   
56   package org.apache.poi.hssf.record;
57   
58   import org.apache.poi.util.HexDump;
59   import org.apache.poi.util.LittleEndian;
60   import org.apache.poi.util.StringUtil;
61   import java.util.Stack;
62   import org.apache.poi.hssf.record.formula.Ptg;
63   import org.apache.poi.hssf.record.formula.Area3DPtg;
64   import org.apache.poi.hssf.record.formula.Ref3DPtg;
65   import java.util.List;
66   import org.apache.poi.hssf.util.RangeAddress;
67   import org.apache.poi.hssf.util.SheetReferences;
68   
69   /**
70    * Title:        Name Record (aka Named Range) <P>
71    * Description:  Defines a named range within a workbook. <P>
72    * REFERENCE:  <P>
73    * @author Libin Roman (Vista Portal LDT. Developer)
74    * @author  Sergei Kozello (sergeikozello at mail.ru)
75    * @version 1.0-pre
76    */
77   
78   public class NameRecord extends Record {
79       /**
80        */
81       public final static short sid = 0x18; //Docs says that it is 0x218
82       private short             field_1_option_flag;
83       private byte              field_2_keyboard_shortcut;
84       private byte              field_3_length_name_text;
85       private short             field_4_length_name_definition;
86       private short             field_5_index_to_sheet;
87       private short             field_6_equals_to_index_to_sheet;
88       private byte              field_7_length_custom_menu;
89       private byte              field_8_length_description_text;
90       private byte              field_9_length_help_topic_text;
91       private byte              field_10_length_status_bar_text;
92       private byte              field_11_compressed_unicode_flag;   // not documented
93       private byte              field_12_builtIn_name;
94       private String            field_12_name_text;
95       private Stack             field_13_name_definition;
96       private byte[]            field_13_raw_name_definition;       // raw data
97       private String            field_14_custom_menu_text;
98       private String            field_15_description_text;
99       private String            field_16_help_topic_text;
100      private String            field_17_status_bar_text;
101  
102      /** Creates new NameRecord */
103      public NameRecord() {
104          field_13_name_definition = new Stack();
105  
106          field_12_name_text = new String();
107          field_14_custom_menu_text = new String();
108          field_15_description_text = new String();
109          field_16_help_topic_text = new String();
110          field_17_status_bar_text = new String();
111      }
112  
113      /**
114       * Constructs a Name record and sets its fields appropriately.
115       *
116       * @param id     id must be 0x18 or an exception will be throw upon validation
117       * @param size  the size of the data area of the record
118       * @param data  data of the record (should not contain sid/len)
119       */
120      public NameRecord(short id, short size, byte [] data) {
121          super(id, size, data);
122      }
123  
124      /**
125       * Constructs a Name record and sets its fields appropriately.
126       *
127       * @param id     id must be 0x18 or an exception will be throw upon validation
128       * @param size  the size of the data area of the record
129       * @param data  data of the record (should not contain sid/len)
130       * @param offset of the record's data
131       */
132      public NameRecord(short id, short size, byte [] data, int offset) {
133          super(id, size, data, offset);
134      }
135  
136      /** sets the option flag for the named range
137       * @param flag option flag
138       */
139      public void setOptionFlag(short flag){
140          field_1_option_flag = flag;
141      }
142  
143      /** sets the keyboard shortcut
144       * @param shortcut keyboard shortcut
145       */
146      public void setKeyboardShortcut(byte shortcut){
147          field_2_keyboard_shortcut = shortcut;
148      }
149  
150      /** sets the name of the named range length
151       * @param length name length
152       */
153      public void setNameTextLength(byte length){
154          field_3_length_name_text = length;
155      }
156  
157      /** sets the definition (reference - formula) length
158       * @param length defenition length
159       */
160      public void setDefinitionTextLength(short length){
161          field_4_length_name_definition = length;
162      }
163  
164      /** sets the index number to the extern sheet (thats is what writen in ducomentetion
165       *  but as i saw , its work direrent)
166       * @param index extern sheet index
167       */
168      public void setIndexToSheet(short index){
169          field_5_index_to_sheet = index;
170  
171          // field_6_equals_to_index_to_sheet is equal to field_5_index_to_sheet
172          field_6_equals_to_index_to_sheet = index;
173      }
174  
175      /** sets the custom menu length
176       * @param length custom menu length
177       */
178      public void setCustomMenuLength(byte length){
179          field_7_length_custom_menu = length;
180      }
181  
182      /** sets the length of named range description
183       * @param length description length
184       */
185      public void setDescriptionTextLength(byte length){
186          field_8_length_description_text = length;
187      }
188  
189      /** sets the help topic length
190       * @param length help topic length
191       */
192      public void setHelpTopicLength(byte length){
193          field_9_length_help_topic_text = length;
194      }
195  
196      /** sets the length of the status bar text
197       * @param length status bar text length
198       */
199      public void setStatusBarLength(byte length){
200          field_10_length_status_bar_text = length;
201      }
202  
203      /** sets the compressed unicode flag
204       * @param flag unicode flag
205       */
206      public void setCompressedUnicodeFlag(byte flag) {
207          field_11_compressed_unicode_flag = flag;
208      }
209  
210      /** sets the name of the named range
211       * @param name named range name
212       */
213      public void setNameText(String name){
214          field_12_name_text = name;
215      }
216  
217      //    public void setNameDefintion(String definition){
218      //        test = definition;
219      //    }
220  
221      /** sets the custom menu text
222       * @param text custom menu text
223       */
224      public void setCustomMenuText(String text){
225          field_14_custom_menu_text = text;
226      }
227  
228      /** sets the description text
229       * @param text the description text
230       */
231      public void setDescriptionText(String text){
232          field_15_description_text = text;
233      }
234  
235      /** sets the help topic text
236       * @param text help topix text
237       */
238      public void setHelpTopicText(String text){
239          field_16_help_topic_text = text;
240      }
241  
242      /** sets the status bar text
243       * @param text status bar text
244       */
245      public void setStatusBarText(String text){
246          field_17_status_bar_text = text;
247      }
248  
249      /** gets the option flag
250       * @return option flag
251       */
252      public short getOptionFlag(){
253          return field_1_option_flag;
254      }
255  
256      /** returns the keyboard shortcut
257       * @return keyboard shortcut
258       */
259      public byte getKeyboardShortcut(){
260          return field_2_keyboard_shortcut ;
261      }
262  
263      /** gets the name length
264       * @return name length
265       */
266      public byte getNameTextLength(){
267          return field_3_length_name_text;
268      }
269  
270      /** get the definition length
271       * @return definition length
272       */
273      public short getDefinitionTextLength(){
274          return field_4_length_name_definition;
275      }
276  
277      /** gets the index to extern sheet
278       * @return index to extern sheet
279       */
280      public short getIndexToSheet(){
281          return field_5_index_to_sheet;
282      }
283  
284      /** gets the custom menu length
285       * @return custom menu length
286       */
287      public byte getCustomMenuLength(){
288          return field_7_length_custom_menu;
289      }
290  
291      /** gets the description text length
292       * @return description text length
293       */
294      public byte getDescriptionTextLength(){
295          return field_8_length_description_text;
296      }
297  
298      /** gets the help topic length
299       * @return help topic length
300       */
301      public byte getHelpTopicLength(){
302          return field_9_length_help_topic_text;
303      }
304  
305      /** get the status bar text length
306       * @return satus bar length
307       */
308      public byte getStatusBarLength(){
309          return field_10_length_status_bar_text;
310      }
311  
312      /** gets the name compressed Unicode flag
313       * @return compressed unicode flag
314       */
315      public byte getCompressedUnicodeFlag() {
316          return field_11_compressed_unicode_flag;
317      }
318  
319      /** gets the name
320       * @return name
321       */
322      public String getNameText(){
323          return field_12_name_text;
324      }
325  
326      /** gets the definition, reference (Formula)
327       * @return definition -- can be null if we cant parse ptgs
328       */
329      protected List getNameDefinition() {
330          return ( List ) field_13_name_definition;
331      }
332  
333      /** get the custom menu text
334       * @return custom menu text
335       */
336      public String getCustomMenuText(){
337          return field_14_custom_menu_text;
338      }
339  
340      /** gets the description text
341       * @return description text
342       */
343      public String getDescriptionText(){
344          return field_15_description_text;
345      }
346  
347      /** get the help topic text
348       * @return gelp topic text
349       */
350      public String getHelpTopicText(){
351          return field_16_help_topic_text;
352      }
353  
354      /** gets the status bar text
355       * @return status bar text
356       */
357      public String getStatusBarText(){
358          return field_17_status_bar_text;
359      }
360  
361      /**
362       * called by constructor, should throw runtime exception in the event of a
363       * record passed with a differing ID.
364       *
365       * @param id alleged id for this record
366       */
367      protected void validateSid(short id) {
368          if (id != sid) {
369              throw new RecordFormatException("NOT A valid Name RECORD");
370          }
371      }
372  
373      /**
374       * called by the class that is responsible for writing this sucker.
375       * Subclasses should implement this so that their data is passed back in a
376       * byte array.
377       *
378       * @param offset to begin writing at
379       * @param data byte array containing instance data
380       * @return number of bytes written
381       */
382      public int serialize(int offset, byte[] data) {
383          LittleEndian.putShort(data, 0 + offset, sid);
384          // size defined below
385          LittleEndian.putShort(data, 4 + offset, getOptionFlag());
386          data[6 + offset] = getKeyboardShortcut();
387          data[7 + offset] = getNameTextLength();
388          LittleEndian.putShort(data, 8 + offset, getDefinitionTextLength());
389          LittleEndian.putShort(data, 10 + offset, getIndexToSheet());
390          LittleEndian.putShort(data, 12 + offset, getIndexToSheet());
391          data [14 + offset] =  getCustomMenuLength();
392          data [15 + offset] =  getDescriptionTextLength();
393          data [16 + offset] =  getHelpTopicLength();
394          data [17 + offset] =  getStatusBarLength();
395          data [18 + offset] =  getCompressedUnicodeFlag();
396          
397        if ( ( field_1_option_flag & (short)0x20 ) != 0 ) {
398            LittleEndian.putShort(data, 2 + offset, (short)( 16 + field_13_raw_name_definition.length ));
399            
400              data [19 + offset] =  field_12_builtIn_name;
401              System.arraycopy( field_13_raw_name_definition, 0, data, 20 + offset, field_13_raw_name_definition.length );
402              
403              return 20 + field_13_raw_name_definition.length;
404        }
405        else {
406            LittleEndian.putShort(data, 2 + offset, (short)( 15 + getTextsLength()));
407            
408            
409              StringUtil.putCompressedUnicode(getNameText(), data , 19 + offset);
410      
411              int start_of_name_definition    = 19  + field_3_length_name_text;
412              if (this.field_13_name_definition != null) {
413                  serializePtgs(data, start_of_name_definition + offset);
414              } else {
415                  System.arraycopy(field_13_raw_name_definition,0,data
416                  ,start_of_name_definition + offset,field_13_raw_name_definition.length);
417              }
418      
419              int start_of_custom_menu_text   = start_of_name_definition + field_4_length_name_definition;
420              StringUtil.putCompressedUnicode(getCustomMenuText(), data , start_of_custom_menu_text + offset);
421      
422              int start_of_description_text   = start_of_custom_menu_text + field_8_length_description_text;
423              StringUtil.putCompressedUnicode(getDescriptionText(), data , start_of_description_text + offset);
424      
425              int start_of_help_topic_text    = start_of_description_text + field_9_length_help_topic_text;
426              StringUtil.putCompressedUnicode(getHelpTopicText(), data , start_of_help_topic_text + offset);
427      
428              int start_of_status_bar_text       = start_of_help_topic_text + field_10_length_status_bar_text;
429              StringUtil.putCompressedUnicode(getStatusBarText(), data , start_of_status_bar_text + offset);
430              
431            return getRecordSize();
432        }
433      }
434  
435      private void serializePtgs(byte [] data, int offset) {
436          int pos = offset;
437  
438          for (int k = 0; k < field_13_name_definition.size(); k++) {
439              Ptg ptg = ( Ptg ) field_13_name_definition.get(k);
440  
441              ptg.writeBytes(data, pos);
442              pos += ptg.getSize();
443          }
444      }
445  
446  
447      /** gets the length of all texts
448       * @return total length
449       */
450      public int getTextsLength(){
451          int result;
452  
453          result = getNameTextLength() + getDefinitionTextLength() + getDescriptionTextLength() +
454          getHelpTopicLength() + getStatusBarLength();
455  
456  
457          return result;
458      }
459  
460      /** returns the record size
461       */
462      public int getRecordSize(){
463          int result;
464  
465          result = 19 + getTextsLength();
466  
467          return result;
468      }
469  
470      /** gets the extern sheet number
471       * @return extern sheet index
472       */
473      public short getExternSheetNumber(){
474          if (field_13_name_definition == null) return 0;
475          Ptg ptg = (Ptg) field_13_name_definition.peek();
476          short result = 0;
477  
478          if (ptg.getClass() == Area3DPtg.class){
479              result = ((Area3DPtg) ptg).getExternSheetIndex();
480  
481          } else if (ptg.getClass() == Ref3DPtg.class){
482              result = ((Ref3DPtg) ptg).getExternSheetIndex();
483          }
484  
485          return result;
486      }
487  
488      /** sets the extern sheet number
489       * @param externSheetNumber extern sheet number
490       */
491      public void setExternSheetNumber(short externSheetNumber){
492          Ptg ptg;
493  
494          if (field_13_name_definition == null || field_13_name_definition.isEmpty()){
495              field_13_name_definition = new Stack();
496              ptg = createNewPtg();
497          } else {
498              ptg = (Ptg) field_13_name_definition.peek();
499          }
500  
501          if (ptg.getClass() == Area3DPtg.class){
502              ((Area3DPtg) ptg).setExternSheetIndex(externSheetNumber);
503  
504          } else if (ptg.getClass() == Ref3DPtg.class){
505              ((Ref3DPtg) ptg).setExternSheetIndex(externSheetNumber);
506          }
507  
508      }
509  
510      private Ptg createNewPtg(){
511          Ptg ptg = new Area3DPtg();
512          field_13_name_definition.push(ptg);
513  
514          return ptg;
515      }
516  
517      /** gets the reference , the area only (range)
518       * @return area reference
519       */
520      public String getAreaReference(SheetReferences refs){
521          if (field_13_name_definition == null) return "#REF!";
522          Ptg ptg = (Ptg) field_13_name_definition.peek();
523          String result = "";
524  
525          if (ptg.getClass() == Area3DPtg.class){
526              result = ((Area3DPtg) ptg).toFormulaString(refs);
527  
528          } else if (ptg.getClass() == Ref3DPtg.class){
529              result = ((Ref3DPtg) ptg).toFormulaString(refs);
530          }
531  
532          return result;
533      }
534  
535      /** sets the reference , the area only (range)
536       * @param ref area reference
537       */
538      public void setAreaReference(String ref){
539          //Trying to find if what ptg do we need
540          RangeAddress ra = new RangeAddress(ref);
541          Ptg oldPtg;
542          Ptg ptg;
543  
544          if (field_13_name_definition==null ||field_13_name_definition.isEmpty()){
545              field_13_name_definition = new Stack();
546              oldPtg = createNewPtg();
547          } else {
548              //Trying to find extern sheet index
549              oldPtg = (Ptg) field_13_name_definition.pop();
550          }
551  
552          short externSheetIndex = 0;
553  
554          if (oldPtg.getClass() == Area3DPtg.class){
555              externSheetIndex =  ((Area3DPtg) oldPtg).getExternSheetIndex();
556  
557          } else if (oldPtg.getClass() == Ref3DPtg.class){
558              externSheetIndex =  ((Ref3DPtg) oldPtg).getExternSheetIndex();
559          }
560  
561          if (ra.hasRange()) {
562              ptg = new Area3DPtg();
563              ((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
564              ((Area3DPtg) ptg).setArea(ref);
565              this.setDefinitionTextLength((short)((Area3DPtg) ptg).getSize());
566          } else {
567              ptg = new Ref3DPtg();
568              ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex);
569              ((Ref3DPtg) ptg).setArea(ref);
570              this.setDefinitionTextLength((short)((Ref3DPtg) ptg).getSize());
571          }
572  
573          field_13_name_definition.push(ptg);
574  
575      }
576  
577      /**
578       * called by the constructor, should set class level fields.  Should throw
579       * runtime exception for bad/icomplete data.
580       *
581       * @param data raw data
582       * @param size size of data
583       * @param offset of the record's data (provided a big array of the file)
584       */
585      protected void fillFields(byte[] data, short size, int offset) {
586          field_1_option_flag             = LittleEndian.getShort(data, 0 + offset);
587          field_2_keyboard_shortcut       = data [2 + offset];
588          field_3_length_name_text        = data [3 + offset];
589          field_4_length_name_definition  = LittleEndian.getShort(data, 4 + offset);
590          field_5_index_to_sheet          = LittleEndian.getShort(data, 6 + offset);
591          field_6_equals_to_index_to_sheet= LittleEndian.getShort(data, 8 + offset);
592          field_7_length_custom_menu      = data [10 + offset];
593          field_8_length_description_text = data [11 + offset];
594          field_9_length_help_topic_text  = data [12 + offset];
595          field_10_length_status_bar_text = data [13 + offset];
596  
597          
598          if ( ( field_1_option_flag & (short)0x20 ) != 0 ) {
599              // DEBUG
600              // System.out.println( "Built-in name" );
601              
602              field_11_compressed_unicode_flag = data[ 14 + offset ];
603              field_12_builtIn_name = data[ 15 + offset ];
604  
605              if ( (field_12_builtIn_name & (short)0x07) != 0 ) {
606                  field_12_name_text = "Print_Titles";
607                  
608                  // DEBUG
609                  // System.out.println( field_12_name_text );
610                  
611                  field_13_raw_name_definition = new byte[ field_4_length_name_definition ];
612                  System.arraycopy( data, 16 + offset, field_13_raw_name_definition, 0, field_13_raw_name_definition.length );
613                  
614                  // DEBUG
615                  // System.out.println( HexDump.toHex( field_13_raw_name_definition ) );
616              }
617          }
618          else {
619      
620              field_11_compressed_unicode_flag= data [14 + offset];
621              field_12_name_text = new String(data, 15 + offset,
622              LittleEndian.ubyteToInt(field_3_length_name_text));
623          
624              int start_of_name_definition    = 15 + field_3_length_name_text;
625              field_13_name_definition = getParsedExpressionTokens(data, field_4_length_name_definition,
626              offset, start_of_name_definition);
627      
628              int start_of_custom_menu_text   = start_of_name_definition + field_4_length_name_definition;
629              field_14_custom_menu_text       = new String(data, start_of_custom_menu_text + offset,
630              LittleEndian.ubyteToInt(field_7_length_custom_menu));
631      
632              int start_of_description_text   = start_of_custom_menu_text + field_8_length_description_text;
633              field_15_description_text       = new String(data, start_of_description_text + offset,
634              LittleEndian.ubyteToInt(field_8_length_description_text));
635      
636              int start_of_help_topic_text    = start_of_description_text + field_9_length_help_topic_text;
637              field_16_help_topic_text        = new String(data, start_of_help_topic_text + offset,
638              LittleEndian.ubyteToInt(field_9_length_help_topic_text));
639      
640              int start_of_status_bar_text       = start_of_help_topic_text + field_10_length_status_bar_text;
641              field_17_status_bar_text        = new String(data, start_of_status_bar_text +  offset,
642              LittleEndian.ubyteToInt(field_10_length_status_bar_text));
643          }
644      }
645  
646      private Stack getParsedExpressionTokens(byte [] data, short size,
647      int offset, int start_of_expression) {
648          Stack stack = new Stack();
649          int   pos           = start_of_expression + offset;
650          int   sizeCounter   = 0;
651          try {
652              while (sizeCounter < size) {
653                  Ptg ptg = Ptg.createPtg(data, pos);
654  
655                  pos += ptg.getSize();
656                  sizeCounter += ptg.getSize();
657                  stack.push(ptg);
658              }
659          } catch (java.lang.UnsupportedOperationException uoe) {
660              System.err.println("[WARNING] Unknown Ptg "
661                      + uoe.getMessage() );
662              field_13_raw_name_definition=new byte[size];
663              System.arraycopy(data,offset,field_13_raw_name_definition,0,size);
664              return null;
665          }
666          return stack;
667      }
668  
669  
670      /**
671       * return the non static version of the id for this record.
672       */
673      public short getSid() {
674          return this.sid;
675      }
676      /*
677        20 00 
678        00 
679        01 
680        1A 00 // sz = 0x1A = 26
681        00 00 
682        01 00 
683        00 
684        00 
685        00 
686        00 
687        00 // unicode flag
688        07 // name
689        
690        29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26
691        00 07 00 07 00 00 00 FF 00 10                   //  }
692        
693        
694        
695        20 00 
696        00 
697        01 
698        0B 00 // sz = 0xB = 11
699        00 00 
700        01 00 
701        00 
702        00 
703        00 
704        00 
705        00 // unicode flag
706        07 // name
707        
708        3B 00 00 07 00 07 00 00 00 FF 00   // { 11 }
709    */
710      /*
711        18, 00, 
712        1B, 00, 
713        
714        20, 00, 
715        00, 
716        01, 
717        0B, 00, 
718        00, 
719        00, 
720        00, 
721        00, 
722        00, 
723        07, 
724        3B 00 00 07 00 07 00 00 00 FF 00 ]     
725       */
726  
727      /**
728       * @see Object#toString()
729       */
730      public String toString() {
731          StringBuffer buffer = new StringBuffer();
732  
733          buffer.append("[NAME]\n");
734          buffer.append("    .option flags         = ").append( HexDump.toHex( field_1_option_flag ) )
735              .append("\n");
736          buffer.append("    .keyboard shortcut    = ").append( HexDump.toHex( field_2_keyboard_shortcut ) )
737              .append("\n");
738          buffer.append("    .length of the name   = ").append( field_3_length_name_text )
739              .append("\n");
740          buffer.append("    .size of the formula data = ").append( field_4_length_name_definition )
741              .append("\n");
742          buffer.append("    .unused                 = ").append( field_5_index_to_sheet )
743              .append("\n");
744          buffer.append("    .( 0 = Global name, otherwise index to sheet (one-based) ) = ").append( field_6_equals_to_index_to_sheet )
745              .append("\n");
746          buffer.append("    .Length of menu text (character count)        = ").append( field_7_length_custom_menu )
747              .append("\n");
748          buffer.append("    .Length of description text (character count) = ").append( field_8_length_description_text )
749              .append("\n");
750          buffer.append("    .Length of help topic text (character count)  = ").append( field_9_length_help_topic_text )
751              .append("\n");
752          buffer.append("    .Length of status bar text (character count)  = ").append( field_10_length_status_bar_text )
753              .append("\n");
754          buffer.append("    .Name (Unicode flag)  = ").append( field_11_compressed_unicode_flag )
755              .append("\n");
756          buffer.append("    .Name (Unicode text)  = ").append( field_12_name_text )
757              .append("\n");
758          buffer.append("    .Formula data (RPN token array without size field)      = ").append( HexDump.toHex( field_13_raw_name_definition ) )
759              .append("\n");
760          buffer.append("    .Menu text (Unicode string without length field)        = ").append( field_14_custom_menu_text )
761              .append("\n");
762          buffer.append("    .Description text (Unicode string without length field) = ").append( field_15_description_text )
763              .append("\n");
764          buffer.append("    .Help topic text (Unicode string without length field)  = ").append( field_16_help_topic_text )
765              .append("\n");
766          buffer.append("    .Status bar text (Unicode string without length field)  = ").append( field_17_status_bar_text )
767              .append("\n");
768          buffer.append("[/NAME]\n");
769          
770          return buffer.toString();
771      }
772  
773  }
774